diff options
398 files changed, 29410 insertions, 12146 deletions
diff --git a/Documentation/Configure.help b/Documentation/Configure.help index fd1366108374..799e354d230b 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -9457,6 +9457,15 @@ CONFIG_TULIP module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. +New Tulip bus configuration (EXPERIMENTAL) +CONFIG_TULIP_MWI + This configures your Tulip card specifically for the card and + system cache line size type you are using. + + This is experimental code, not yet tested on many boards. + + If unsure, say N. + Digi Intl. RightSwitch support CONFIG_DGRS This is support for the Digi International RightSwitch series of @@ -12180,12 +12189,13 @@ CONFIG_NTFS_RW If unsure, say N. -System V and Coherent file system support (read only) +System V, Version 7, Xenix and Coherent filesystem support (read only) CONFIG_SYSV_FS SCO, Xenix and Coherent are commercial Unix systems for Intel - machines. Saying Y here would allow you to read from their floppies - and hard disk partitions. If you also want to write to these media, - say Y to "SYSV file system write support" below. + machines, and Version 7 was used on the DEC PDP-11. Saying Y + here would allow you to read from their floppies and hard disk + partitions. If you also want to write to these media, say Y to + "SYSV file system write support" below. If you have floppies or hard disk partitions like that, it is likely that they contain binaries from those other Unix systems; in order @@ -12194,7 +12204,9 @@ CONFIG_SYSV_FS Xenix, Wyse, UnixWare, Dell Unix and System V programs under Linux and is often needed to run commercial software that's only available for those systems. It's available via FTP (user: anonymous) from - ftp://tsx-11.mit.edu/pub/linux/BETA ). + ftp://tsx-11.mit.edu/pub/linux/BETA ). NOTE: that will work only for + binaries from Intel-based systems; PDP ones will have to wait until + somebody ports Linux to -11 ;-) If you only intend to mount files from some other Unix over the network using NFS, you don't need the System V file system support @@ -16128,6 +16140,20 @@ CONFIG_ISDN_DRV_ACT2000 isdn4k-utils package. Please read the file Documentation/isdn/README.act2000 for more information. +Auvertech TurboPAM support +CONFIG_ISDN_DRV_TPAM + This enables support for the Auvertech TurboPAM ISDN-card. + For running this card, additional firmware is necessary, which has + to be downloaded into the card using a utility which is distributed + separately from the Auvertech's web site: http://www.auvertech.fr. + + Please redirect all support questions to support@auvertech.fr. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called tpam.o. + Hypercope HYSDN cards (Champ, Ergo, Metro) support (module) CONFIG_HYSDN Say Y here if you have one of Hypercope's active PCI ISDN cards diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 569f70915dd9..d2b63417e0b9 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -1,7 +1,7 @@ BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \ kernel-api.sgml parportbook.sgml kernel-hacking.sgml \ kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \ - deviceiobook.sgml + deviceiobook.sgml procfs-guide.sgml PS := $(patsubst %.sgml, %.ps, $(BOOKS)) PDF := $(patsubst %.sgml, %.pdf, $(BOOKS)) @@ -9,6 +9,7 @@ HTML := $(patsubst %.sgml, %, $(BOOKS)) IMG-parportbook := parport-share.fig parport-multi.fig parport-structure.fig EPS-parportbook := $(patsubst %.fig, %.eps, $(IMG-parportbook)) JPG-parportbook := $(patsubst %.fig, %.jpeg, $(IMG-parportbook)) +C-procfs-example = procfs_example.sgml books: $(BOOKS) @@ -28,6 +29,15 @@ html: $(HTML) %.jpeg: %.fig -fig2dev -Ljpeg $< $@ +%.sgml: %.c + echo "<programlisting>" > $@ + expand --tabs=8 < $< | \ + sed -e "s/&/\\&/g" \ + -e "s/</\\</g" \ + -e "s/>/\\>/g" >> $@ + echo "</programlisting>" >> $@ + + $(TOPDIR)/scripts/docproc: $(MAKE) -C $(TOPDIR)/scripts docproc @@ -67,6 +77,9 @@ videobook.sgml: videobook.tmpl $(TOPDIR)/drivers/media/video/videodev.c $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/media/video/videodev.c \ <videobook.tmpl >videobook.sgml +procfs-guide.sgml: procfs-guide.tmpl procfs_example.sgml + $(TOPDIR)/scripts/docgen < procfs-guide.tmpl >$@ + APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \ $(TOPDIR)/arch/i386/kernel/irq.c \ $(TOPDIR)/arch/i386/kernel/mca.c \ @@ -128,6 +141,7 @@ clean: -$(RM) $(BOOKS) -$(RM) $(DVI) $(AUX) $(TEX) $(LOG) $(OUT) -$(RM) $(JPG-parportbook) $(EPS-parportbook) + -$(RM) $(C-procfs-example) mrproper: clean -$(RM) $(PS) $(PDF) diff --git a/Documentation/DocBook/procfs-guide.tmpl b/Documentation/DocBook/procfs-guide.tmpl new file mode 100644 index 000000000000..6f9496ac9cee --- /dev/null +++ b/Documentation/DocBook/procfs-guide.tmpl @@ -0,0 +1,625 @@ +<!-- -*- sgml -*- --> +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[ +<!ENTITY procfsexample SYSTEM "procfs_example.sgml"> +]> + +<book id="LKProcfsGuide"> + <bookinfo> + <title>Linux Kernel Procfs Guide</title> + + <authorgroup> + <author> + <firstname>Erik</firstname> + <othername>(J.A.K.)</othername> + <surname>Mouw</surname> + <affiliation> + <orgname>Delft University of Technology</orgname> + <orgdiv>Faculty of Information Technology and Systems</orgdiv> + <address> + <email>J.A.K.Mouw@its.tudelft.nl</email> + <pob>PO BOX 5031</pob> + <postcode>2600 GA</postcode> + <city>Delft</city> + <country>The Netherlands</country> + </address> + </affiliation> + </author> + </authorgroup> + + <revhistory> + <revision> + <revnumber>1.0 </revnumber> + <date>May 30, 2001</date> + <revremark>Initial revision posted to linux-kernel</revremark> + </revision> + <revision> + <revnumber>1.1 </revnumber> + <date>June 3, 2001</date> + <revremark>Revised after comments from linux-kernel</revremark> + </revision> + </revhistory> + + <copyright> + <year>2001</year> + <holder>Erik Mouw</holder> + </copyright> + + + <legalnotice> + <para> + This documentation is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later + version. + </para> + + <para> + This documentation is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the GNU General Public License for more details. + </para> + + <para> + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + </para> + + <para> + For more details see the file COPYING in the source + distribution of Linux. + </para> + </legalnotice> + </bookinfo> + + + + + <toc> + </toc> + + + + + <preface> + <title>Preface</title> + + <para> + This guide describes the use of the procfs file system from + within the Linux kernel. The idea to write this guide came up on + the #kernelnewbies IRC channel (see <ulink + url="http://www.kernelnewbies.org/">http://www.kernelnewbies.org/</ulink>), + when Jeff Garzik explained the use of procfs and forwarded me a + message Alexander Viro wrote to the linux-kernel mailing list. I + agreed to write it up nicely, so here it is. + </para> + + <para> + I'd like to thank Jeff Garzik + <email>jgarzik@mandrakesoft.com</email> and Alexander Viro + <email>viro@math.psu.edu</email> for their input, Tim Waugh + <email>twaugh@redhat.com</email> for his <ulink + url="http://people.redhat.com/twaugh/docbook/selfdocbook/">Selfdocbook</ulink>, + and Marc Joosen <email>marcj@historia.et.tudelft.nl</email> for + proofreading. + </para> + + <para> + This documentation was written while working on the LART + computing board (<ulink + url="http://www.lart.tudelft.nl/">http://www.lart.tudelft.nl/</ulink>), + which is sponsored by the Mobile Multi-media Communications + (<ulink + url="http://www.mmc.tudelft.nl/">http://www.mmc.tudelft.nl/</ulink>) + and Ubiquitous Communications (<ulink + url="http://www.ubicom.tudelft.nl/">http://www.ubicom.tudelft.nl/</ulink>) + projects. + </para> + + <para> + Erik + </para> + </preface> + + + + + <chapter id="intro"> + <title>Introduction</title> + + <para> + The <filename class="directory">/proc</filename> file system + (procfs) is a special file system in the linux kernel. It's a + virtual file system: it is not associated with a block device + but exists only in memory. The files in the procfs are there to + allow userland programs access to certain information from the + kernel (like process information in <filename + class="directory">/proc/[0-9]+/</filename>), but also for debug + purposes (like <filename>/proc/ksyms</filename>). + </para> + + <para> + This guide describes the use of the procfs file system from + within the Linux kernel. It starts by introducing all relevant + functions to manage the files within the file system. After that + it shows how to communicate with userland, and some tips and + tricks will be pointed out. Finally a complete example will be + shown. + </para> + + <para> + Note that the files in <filename + class="directory">/proc/sys</filename> are sysctl files: they + don't belong to procfs and are governed by a completely + different API described in the Kernel API book. + </para> + </chapter> + + + + + <chapter id="managing"> + <title>Managing procfs entries</title> + + <para> + This chapter describes the functions that various kernel + components use to populate the procfs with files, symlinks, + device nodes, and directories. + </para> + + <para> + A minor note before we start: if you want to use any of the + procfs functions, be sure to include the correct header file! + This should be one of the first lines in your code: + </para> + + <programlisting> +#include <linux/proc_fs.h> + </programlisting> + + + + + <sect1 id="regularfile"> + <title>Creating a regular file</title> + + <funcsynopsis> + <funcprototype> + <funcdef>struct proc_dir_entry* <function>create_proc_entry</function></funcdef> + <paramdef>const char* <parameter>name</parameter></paramdef> + <paramdef>mode_t <parameter>mode</parameter></paramdef> + <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef> + </funcprototype> + </funcsynopsis> + + <para> + This function creates a regular file with the name + <parameter>name</parameter>, file mode + <parameter>mode</parameter> in the directory + <parameter>parent</parameter>. To create a file in the root of + the procfs, use <constant>NULL</constant> as + <parameter>parent</parameter> parameter. When successful, the + function will return a pointer to the freshly created + <structname>struct proc_dir_entry</structname>; otherwise it + will return <constant>NULL</constant>. <xref + linkend="userland"> describes how to do something useful with + regular files. + <para> + + <para> + Note that it is specifically supported that you can pass a + path that spans multiple directories. For example + <function>create_proc_entry</function>(<parameter>"drivers/via0/info"</parameter>) + will create the <filename class="directory">via0</filename> + directory if necessary, with standard + <constant>0755</constant> permissions. + </para> + + <para> + If you only want to be able to read the file, the function + <function>create_proc_read_entry</function> described in <xref + linkend="convenience"> may be used to create and initialise + the procfs entry in one single call. + </para> + </sect1> + + + + + <sect1> + <title>Creating a symlink</title> + + <funcsynopsis> + <funcprototype> + <funcdef>struct proc_dir_entry* + <function>proc_symlink</function></funcdef> <paramdef>const + char* <parameter>name</parameter></paramdef> + <paramdef>struct proc_dir_entry* + <parameter>parent</parameter></paramdef> <paramdef>const + char* <parameter>dest</parameter></paramdef> + </funcprototype> + </funcsynopsis> + + <para> + This creates a symlink in the procfs directory + <parameter>parent</parameter> that points from + <parameter>name</parameter> to + <parameter>dest</parameter>. This translates in userland to + <literal>ln -s</literal> <parameter>dest</parameter> + <parameter>name</parameter>. + </para> + </sect1> + + + + + <sect1> + <title>Creating a device</title> + + <funcsynopsis> + <funcprototype> + <funcdef>struct proc_dir_entry* <function>proc_mknod</function></funcdef> + <paramdef>const char* <parameter>name</parameter></paramdef> + <paramdef>mode_t <parameter>mode</parameter></paramdef> + <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef> + <paramdef>kdev_t <parameter>rdev</parameter></paramdef> + </funcprototype> + </funcsynopsis> + + <para> + Creates a device file <parameter>name</parameter> with mode + <parameter>mode</parameter> in the procfs directory + <parameter>parent</parameter>. The device file will work on + the device <parameter>rdev</parameter>, which can be generated + by using the <literal>MKDEV</literal> macro from + <literal>linux/kdev_t.h</literal>. The + <parameter>mode</parameter> parameter + <emphasis>must</emphasis> contain <constant>S_IFBLK</constant> + or <constant>S_IFCHR</constant> to create a device + node. Compare with userland <literal>mknod + --mode=</literal><parameter>mode</parameter> + <parameter>name</parameter> <parameter>rdev</parameter>. + </para> + </sect1> + + + + + <sect1> + <title>Creating a directory</title> + + <funcsynopsis> + <funcprototype> + <funcdef>struct proc_dir_entry* <function>proc_mkdir</function></funcdef> + <paramdef>const char* <parameter>name</parameter></paramdef> + <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef> + </funcprototype> + </funcsynopsis> + + <para> + Create a directory <parameter>name</parameter> in the procfs + directory <parameter>parent</parameter>. + </para> + </sect1> + + + + + <sect1> + <title>Removing an entry</title> + + <funcsynopsis> + <funcprototype> + <funcdef>void <function>remove_proc_entry</function></funcdef> + <paramdef>const char* <parameter>name</parameter></paramdef> + <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef> + </funcprototype> + </funcsynopsis> + + <para> + Removes the entry <parameter>name</parameter> in the directory + <parameter>parent</parameter> from the procfs. Entries are + removed by their <emphasis>name</emphasis>, not by the + <structname>struct proc_dir_entry</structname> returned by the + various create functions. Note that this function doesn't + recursively remove entries. + </para> + + <para> + Be sure to free the <structfield>data</structfield> entry from + the <structname>struct proc_dir_entry</structname> before + <function>remove_proc_entry</function> is called (that is: if + there was some <structfield>data</structfield> allocated, of + course). See <xref linkend="usingdata"> for more information + on using the <structfield>data</structfield> entry. + </para> + </sect1> + </chapter> + + + + + <chapter id="userland"> + <title>Communicating with userland</title> + + <para> + Instead of reading (or writing) information directly from + kernel memory, procfs works with <emphasis>call back + functions</emphasis> for files: functions that are called when + a specific file is being read or written. Such functions have + to be initialised after the procfs file is created by setting + the <structfield>read_proc</structfield> and/or + <structfield>write_proc</structfield> fields in the + <structname>struct proc_dir_entry*</structname> that the + function <function>create_proc_entry</function> returned: + </para> + + <programlisting> +struct proc_dir_entry* entry; + +entry->read_proc = read_proc_foo; +entry->write_proc = write_proc_foo; + </programlisting> + + <para> + If you only want to use a the + <structfield>read_proc</structfield>, the function + <function>create_proc_read_entry</function> described in <xref + linkend="convenience"> may be used to create and initialise the + procfs entry in one single call. + </para> + + + + <sect1> + <title>Reading data</title> + + <para> + The read function is a call back function that allows userland + processes to read data from the kernel. The read function + should have the following format: + </para> + + <funcsynopsis> + <funcprototype> + <funcdef>int <function>read_func</function></funcdef> + <paramdef>char* <parameter>page</parameter></paramdef> + <paramdef>char** <parameter>start</parameter></paramdef> + <paramdef>off_t <parameter>off</parameter></paramdef> + <paramdef>int <parameter>count</parameter></paramdef> + <paramdef>int* <parameter>eof</parameter></paramdef> + <paramdef>void* <parameter>data</parameter></paramdef> + </funcprototype> + </funcsynopsis> + + <para> + The read function should write its information into the + <parameter>page</parameter>. For proper use, the function + should start writing at an offset of + <parameter>off</parameter> in <parameter>page</parameter> and + write at most <parameter>count</parameter> bytes, but because + most read functions are quite simple and only return a small + amount of information, these two parameters are usually + ignored (it breaks pagers like <literal>more</literal> and + <literal>less</literal>, but <literal>cat</literal> still + works). + </para> + + <para> + If the <parameter>off</parameter> and + <parameter>count</parameter> parameters are properly used, + <parameter>eof</parameter> should be used to signal that the + end of the file has been reached by writing + <literal>1</literal> to the memory location + <parameter>eof</parameter> points to. + </para> + + <para> + The parameter <parameter>start</parameter> doesn't seem to be + used anywhere in the kernel. The <parameter>data</parameter> + parameter can be used to create a single call back function for + several files, see <xref linkend="usingdata">. + </para> + + <para> + The <function>read_func</function> function must return the + number of bytes written into the <parameter>page</parameter>. + </para> + + <para> + <xref linkend="example"> shows how to use a read call back + function. + </para> + </sect1> + + + + + <sect1> + <title>Writing data</title> + + <para> + The write call back function allows a userland process to write + data to the kernel, so it has some kind of control over the + kernel. The write function should have the following format: + </para> + + <funcsynopsis> + <funcprototype> + <funcdef>int <function>write_func</function></funcdef> + <paramdef>struct file* <parameter>file</parameter></paramdef> + <paramdef>const char* <parameter>buffer</parameter></paramdef> + <paramdef>unsigned long <parameter>count</parameter></paramdef> + <paramdef>void* <parameter>data</parameter></paramdef> + </funcprototype> + </funcsynopsis> + + <para> + The write function should read <parameter>count</parameter> + bytes at maximum from the <parameter>buffer</parameter>. Note + that the <parameter>buffer</parameter> doesn't live in the + kernel's memory space, so it should first be copied to kernel + space with <function>copy_from_user</function>. The + <parameter>file</parameter> parameter is usually + ignored. <xref linkend="usingdata"> shows how to use the + <parameter>data</parameter> parameter. + </para> + + <para> + Again, <xref linkend="example"> shows how to use this call back + function. + </para> + </sect1> + + + + + <sect1 id="usingdata"> + <title>A single call back for many files</title> + + <para> + When a large number of almost identical files is used, it's + quite inconvenient to use a separate call back function for + each file. A better approach is to have a single call back + function that distinguishes between the files by using the + <structfield>data</structfield> field in <structname>struct + proc_dir_entry</structname>. First of all, the + <structfield>data</structfield> field has to be initialised: + </para> + + <programlisting> +struct proc_dir_entry* entry; +struct my_file_data *file_data; + +file_data = kmalloc(sizeof(struct my_file_data), GFP_KERNEL); +entry->data = file_data; + </programlisting> + + <para> + The <structfield>data</structfield> field is a <type>void + *</type>, so it can be initialised with anything. + </para> + + <para> + Now that the <structfield>data</structfield> field is set, the + <function>read_proc</function> and + <function>write_proc</function> can use it to distinguish + between files because they get it passed into their + <parameter>data</parameter> parameter: + </para> + + <programlisting> +int foo_read_func(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + if(data == file_data) { + /* special case for this file */ + } else { + /* normal processing */ + } + + return len; +} + </programlisting> + + <para> + Be sure to free the <structfield>data</structfield> data field + when removing the procfs entry. + </para> + </sect1> + </chapter> + + + + + <chapter id="tips"> + <title>Tips and tricks</title> + + + + + <sect1 id="convenience"> + <title>Convenience functions</title> + + <funcsynopsis> + <funcprototype> + <funcdef>struct proc_dir_entry* <function>create_proc_read_entry</function></funcdef> + <paramdef>const char* <parameter>name</parameter></paramdef> + <paramdef>mode_t <parameter>mode</parameter></paramdef> + <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef> + <paramdef>read_proc_t* <parameter>read_proc</parameter></paramdef> + <paramdef>void* <parameter>data</parameter></paramdef> + </funcprototype> + </funcsynopsis> + + <para> + This function creates a regular file in exactly the same way + as <function>create_proc_entry</function> from <xref + linkend="regularfile"> does, but also allows to set the read + function <parameter>read_proc</parameter> in one call. This + function can set the <parameter>data</parameter> as well, like + explained in <xref linkend="usingdata">. + </para> + </sect1> + + + + <sect1> + <title>Modules</title> + + <para> + If procfs is being used from within a module, be sure to set + the <structfield>owner</structfield> field in the + <structname>struct proc_dir_entry</structname> to + <constant>THIS_MODULE</constant>. + <para> + + <programlisting> +struct proc_dir_entry* entry; + +entry->owner = THIS_MODULE; + </programlisting> + </sect1> + + + + + <sect1> + <title>Mode and ownership</title> + + <para> + Sometimes it is useful to change the mode and/or ownership of + a procfs entry. Here is an example that shows how to achieve + that: + </para> + + <programlisting> +struct proc_dir_entry* entry; + +entry->mode = S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH; +entry->uid = 0; +entry->gid = 100; + </programlisting> + + </sect1> + </chapter> + + + + + <chapter id="example"> + <title>Example</title> + + <!-- be careful with the example code: it shouldn't be wider than + approx. 60 columns, or otherwise it won't fit properly on a page + --> + +&procfsexample; + + </chapter> +</book> diff --git a/Documentation/DocBook/procfs_example.c b/Documentation/DocBook/procfs_example.c new file mode 100644 index 000000000000..4b46e0e003fb --- /dev/null +++ b/Documentation/DocBook/procfs_example.c @@ -0,0 +1,249 @@ +/* + * procfs_example.c: an example proc interface + * + * Copyright (C) 2001, Erik Mouw (J.A.K.Mouw@its.tudelft.nl) + * + * This file accompanies the procfs-guide in the Linux kernel + * source. Its main use is to demonstrate the concepts and + * functions described in the guide. + * + * This software has been developed while working on the LART + * computing board (http://www.lart.tudelft.nl/), which is + * sponsored by the Mobile Multi-media Communications + * (http://www.mmc.tudelft.nl/) and Ubiquitous Communications + * (http://www.ubicom.tudelft.nl/) projects. + * + * The author can be reached at: + * + * Erik Mouw + * Information and Communication Theory Group + * Faculty of Information Technology and Systems + * Delft University of Technology + * P.O. Box 5031 + * 2600 GA Delft + * The Netherlands + * + * + * This program is free software; you can redistribute + * it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, + * Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <linux/sched.h> +#include <asm/uaccess.h> + + +#define MODULE_VERSION "1.0" +#define MODULE_NAME "procfs_example" + +#define FOOBAR_LEN 8 + +struct fb_data_t { + char name[FOOBAR_LEN + 1]; + char value[FOOBAR_LEN + 1]; +}; + + +static struct proc_dir_entry *example_dir, *foo_file, + *bar_file, *jiffies_file, *tty_device, *symlink; + + +struct fb_data_t foo_data, bar_data; + + +static int proc_read_jiffies(char *page, char **start, + off_t off, int count, + int *eof, void *data) +{ + int len; + + MOD_INC_USE_COUNT; + + len = sprintf(page, "jiffies = %ld\n", + jiffies); + + MOD_DEC_USE_COUNT; + + return len; +} + + +static int proc_read_foobar(char *page, char **start, + off_t off, int count, + int *eof, void *data) +{ + int len; + struct fb_data_t *fb_data = (struct fb_data_t *)data; + + MOD_INC_USE_COUNT; + + len = sprintf(page, "%s = '%s'\n", + fb_data->name, fb_data->value); + + MOD_DEC_USE_COUNT; + + return len; +} + + +static int proc_write_foobar(struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int len; + struct fb_data_t *fb_data = (struct fb_data_t *)data; + + MOD_INC_USE_COUNT; + + if(count > FOOBAR_LEN) + len = FOOBAR_LEN; + else + len = count; + + if(copy_from_user(fb_data->value, buffer, len)) { + MOD_DEC_USE_COUNT; + return -EFAULT; + } + + fb_data->value[len] = '\0'; + + MOD_DEC_USE_COUNT; + + return len; +} + + +static int __init init_procfs_example(void) +{ + int rv = 0; + + /* create directory */ + example_dir = proc_mkdir(MODULE_NAME, NULL); + if(example_dir == NULL) { + rv = -ENOMEM; + goto out; + } + + example_dir->owner = THIS_MODULE; + + /* create jiffies using convenience function */ + jiffies_file = create_proc_read_entry("jiffies", + 0444, example_dir, + proc_read_jiffies, + NULL); + if(jiffies_file == NULL) { + rv = -ENOMEM; + goto no_jiffies; + } + + jiffies_file->owner = THIS_MODULE; + + /* create foo and bar files using same callback + * functions + */ + foo_file = create_proc_entry("foo", 0644, example_dir); + if(foo_file == NULL) { + rv = -ENOMEM; + goto no_foo; + } + + strcpy(foo_data.name, "foo"); + strcpy(foo_data.value, "foo"); + foo_file->data = &foo_data; + foo_file->read_proc = proc_read_foobar; + foo_file->write_proc = proc_write_foobar; + foo_file->owner = THIS_MODULE; + + bar_file = create_proc_entry("bar", 0644, example_dir); + if(bar_file == NULL) { + rv = -ENOMEM; + goto no_bar; + } + + strcpy(bar_data.name, "bar"); + strcpy(bar_data.value, "bar"); + bar_file->data = &bar_data; + bar_file->read_proc = proc_read_foobar; + bar_file->write_proc = proc_write_foobar; + bar_file->owner = THIS_MODULE; + + /* create tty device */ + tty_device = proc_mknod("tty", S_IFCHR | 0666, + example_dir, MKDEV(5, 0)); + if(tty_device == NULL) { + rv = -ENOMEM; + goto no_tty; + } + + tty_device->owner = THIS_MODULE; + + /* create symlink */ + symlink = proc_symlink("jiffies_too", example_dir, + "jiffies"); + if(symlink == NULL) { + rv = -ENOMEM; + goto no_symlink; + } + + symlink->owner = THIS_MODULE; + + /* everything OK */ + printk(KERN_INFO "%s %s initialised\n", + MODULE_NAME, MODULE_VERSION); + return 0; + +no_symlink: + remove_proc_entry("tty", example_dir); +no_tty: + remove_proc_entry("bar", example_dir); +no_bar: + remove_proc_entry("foo", example_dir); +no_foo: + remove_proc_entry("jiffies", example_dir); +no_jiffies: + remove_proc_entry(MODULE_NAME, NULL); +out: + return rv; +} + + +static void __exit cleanup_procfs_example(void) +{ + remove_proc_entry("jiffies_too", example_dir); + remove_proc_entry("tty", example_dir); + remove_proc_entry("bar", example_dir); + remove_proc_entry("foo", example_dir); + remove_proc_entry("jiffies", example_dir); + remove_proc_entry(MODULE_NAME, NULL); + + printk(KERN_INFO "%s %s removed\n", + MODULE_NAME, MODULE_VERSION); +} + + +module_init(init_procfs_example); +module_exit(cleanup_procfs_example); + +MODULE_AUTHOR("Erik Mouw"); +MODULE_DESCRIPTION("procfs examples"); + +EXPORT_NO_SYMBOLS; diff --git a/Documentation/fb/matroxfb.txt b/Documentation/fb/matroxfb.txt index a3bbe6b92c64..83b529fd64da 100644 --- a/Documentation/fb/matroxfb.txt +++ b/Documentation/fb/matroxfb.txt @@ -173,9 +173,9 @@ nomtrr - disables write combining on frame buffer. This slows down driver but mtrr - enables write combining on frame buffer. It speeds up video accesses much. It is default. You must have MTRR support enabled in kernel and your CPU must have MTRR (f.e. Pentium II have them). -sgram - tells to driver that you have G200 with SGRAM memory. It has no +sgram - tells to driver that you have Gxx0 with SGRAM memory. It has no effect without `init'. -sdram - tells to driver that you have G200 with SDRAM memory. +sdram - tells to driver that you have Gxx0 with SDRAM memory. It is a default. inv24 - change timings parameters for 24bpp modes on Millenium and Millenium II. Specify this if you see strange color shadows around @@ -279,7 +279,7 @@ Currently there are following known bugs: + 24bpp does not support correctly XF-FBDev on big-endian architectures. + interlaced text mode is not supported; it looks like hardware limitation, but I'm not sure. - + G200 SGRAM/SDRAM is not autodetected. + + Gxx0 SGRAM/SDRAM is not autodetected. + maybe more... And following misfeatures: + SVGALib does not restore screen on exit. @@ -336,7 +336,7 @@ NOACCEL ACCEL, nofastfont 8x16 12x22 6x11 - Millennium I G200 Millennium I G200 Millennium I G200 + Millennium I G200 Millennium I G200 Millennium I G200 8bpp 7.79 7.24 13.55 7.78 30.00 21.01 16bpp 9.13 7.78 16.16 7.78 30.00 21.01 24bpp 14.17 10.72 18.69 10.24 34.99 21.01 @@ -344,7 +344,7 @@ ACCEL, nofastfont ACCEL, fastfont 8x16 12x22 6x11 - Millennium I G200 Millennium I G200 Millennium I G200 + Millennium I G200 Millennium I G200 Millennium I G200 8bpp 8.41 6.01 6.54 4.37 16.00 10.51 16bpp 9.54 9.12 8.76 6.17 17.52 14.01 24bpp 15.00 12.36 11.67 10.00 22.01 18.32 @@ -355,6 +355,8 @@ TEXT Millennium I G200 TEXT 3.29 1.50 +* Yes, it is slower than Millennium I. + Dualhead G400 ============= @@ -376,7 +378,22 @@ Driver supports dualhead G400 with some limitations: + if you compiled it as module, you must insert i2c-matroxfb, matroxfb_maven and matroxfb_crtc2 into kernel. + +Dualhead G450 +============= +Driver supports dualhead G450 with some limitations: + + secondary head shares videomemory with primary head. It is not problem + if you have 32MB of videoram, but if you have only 16MB, you may have + to think twice before choosing videomode. + + due to hardware limitation, secondary head can use only 16 and 32bpp + videomodes. + + secondary head is not accelerated. + + secondary head always powerups in 640x480@60-32 videomode. You have to use + fbset to change this mode. + + TV output is not supported + + kernel is not fully multihead ready, so some things are impossible to do. + + if you compiled it as module, you must insert matroxfb_g450 and matroxfb_crtc2 + into kernel. -* Yes, it is slower than Millennium I. -- Petr Vandrovec <vandrove@vc.cvut.cz> diff --git a/Documentation/networking/TODO b/Documentation/networking/TODO index 9106a69c2f1d..66d36ff14bae 100644 --- a/Documentation/networking/TODO +++ b/Documentation/networking/TODO @@ -14,3 +14,5 @@ To-do items for network drivers * Add ETHTOOL_GDRVINFO ioctl support to all ethernet drivers. +* dmfe PCI DMA is totally wrong and only works on x86 + diff --git a/Documentation/networking/sk98lin.txt b/Documentation/networking/sk98lin.txt index 9591c7e396f7..170e3fc40d43 100644 --- a/Documentation/networking/sk98lin.txt +++ b/Documentation/networking/sk98lin.txt @@ -1,16 +1,17 @@ -(C)Copyright 1999-2000 SysKonnect. +(C)Copyright 1999-2001 SysKonnect GmbH. +All rights reserved =========================================================================== -sk98lin.txt created 12-Sept-2000 +sk98lin.txt created 28-May-2001 -Readme File for sk98lin.o v3.05 -SK-NET Gigabit Ethernet Adapter SK-98xx Driver for Linux +Readme File for sk98lin v4.06 +SK-NET Gigabit Ethernet PCI driver for LINUX This file contains (1) OVERVIEW (2) REQUIRED FILES (3) INSTALLATION -(4) INCLUSION OF THE ADAPTER AT SYSTEM START +(4) INCLUSION OF ADAPTER AT SYSTEM START (5) DRIVER PARAMETERS (6) LARGE FRAME SUPPORT (7) TROUBLESHOOTING @@ -19,13 +20,12 @@ This file contains =========================================================================== - (1) OVERVIEW ============ The sk98lin driver supports the SysKonnect SK-NET Gigabit Ethernet Adapter SK-98xx family on Linux 2.2.x and above. -It has been tested with Linux on Intel/x86, ALPHA and UltraSPARC machines. +It has been tested with Linux on Intel/x86 machines. From v3.02 on, the driver is integrated in the linux kernel source. *** @@ -64,8 +64,8 @@ NOTE 2: IMPORTANT: In case of problems, please read the section "make modules_install". Reboot your system. -4) Load the module manually by entering: - insmod sk98lin.o +2) Load the module manually by entering: + modprobe sk98lin If the SysKonnect SK-98xx adapter is installed in your computer and you have a /proc filesystem, running the command 'more /proc/net/dev' should produce an output containing a @@ -75,7 +75,7 @@ NOTE 2: IMPORTANT: In case of problems, please read the section NOTE 1: If you have more than one SysKonnect SK-98xx adapter, the adapters will be listed as 'eth0', 'eth1', 'eth2', etc. - For each adapter, repeat the steps 5) and 6). + For each adapter, repeat the steps 3) and 4). NOTE 2: If you have other Ethernet adapters installed, your SysKonnect SK-98xx adapter can be mapped to 'eth1' or 'eth2' ... @@ -84,7 +84,7 @@ NOTE 2: IMPORTANT: In case of problems, please read the section for each adapter that is found, containing the corresponding 'ethX'. -5) Select an IP address and assign it to the respective adapter by +3) Select an IP address and assign it to the respective adapter by entering: ifconfig eth0 <ip-address> This causes the adapter to connect to the ethernet. The solitary @@ -99,22 +99,22 @@ NOTE 2: IMPORTANT: In case of problems, please read the section NOTE: If you are in doubt about IP addresses, ask your network administrator for assistance. -6) Your adapter should now be fully operational. +4) Your adapter should now be fully operational. Use 'ping <otherstation>' to verify the connection to other computers on your network. - By entering 'ifconfig', you can check the number of packets sent - and received by your adapter and additional some other information - regarding the adapter configuration. + By viewing /proc/net/sk98lin/[devicename], you can check some + information regarding to the adapter configuration. + -7) The driver module can be stopped and unloaded using the following +5) The driver module can be stopped and unloaded using the following commands: ifconfig eth0 down rmmod sk98lin *** -(4) INCLUSION OF THE ADAPTER AT SYSTEM START -============================================ +(4) INCLUSION OF ADAPTER AT SYSTEM START +======================================== Since a large number of different Linux distributions are available, we are unable to describe a general installation procedure @@ -129,7 +129,7 @@ Refer to the distribution's manual for installation of ethernet adapters. ===================== Parameters can be set at the command line while loading the -module with 'insmod'. The configuration tools of some distributions +module with 'modprobe'. The configuration tools of some distributions can also give parameters to the driver module. If you use the kernel module loader, you can set driver parameters in the file /etc/modules.conf (or old name: /etc/conf.modules). @@ -138,12 +138,12 @@ Insert a line of the form: options sk98lin ... For "...", use the same syntax as described below for the command -line parameters of insmod. +line paramaters of modprobe. You either have to reboot your computer or unload and reload the driver to activate the new parameters. The syntax of the driver parameters is: -insmod sk98lin parameter=value1[,value2[,value3...]] +modprobe sk98lin parameter=value1[,value2[,value3...]] value1 is for the first adapter, value2 for the second one etc. All Parameters are case sensitive, so write them exactly as @@ -156,7 +156,7 @@ Sample: Suppose you have two adapters. You want to set AutoNegotiation adapter to FULL and on Port A of the second adapter to HALF. You must enter: - insmod sk98lin.o AutoNeg_A=On,Off DupCap_A=Full,Half + modprobe sk98lin AutoNeg_A=On,Off DupCap_A=Full,Half NOTE: The number of adapters that can be configured this way is limited in the driver (file skge.c, constant SK_MAX_CARD_PARAM). @@ -187,7 +187,7 @@ which you set the parameter (A or B). this port is not "Sense". If autonegotiation is "On", all three values are possible. If it is "Off", only "Full" and "Half" are allowed. - It is useful if your link partner does not support all + It is usefull if your link partner does not support all possible combinations. - Flow Control @@ -234,7 +234,7 @@ which you set the parameter (A or B). - RLMT (Redundant Link Management Technology) Mode Parameter: RlmtMode - Values: CheckLinkState,CheckLocalPort, CheckSeg + Values: CheckLinkState,CheckLocalPort, CheckSeg, DualNet Default: CheckLinkState RLMT (the driver part that decides which port to use) knows three @@ -257,6 +257,13 @@ which you set the parameter (A or B). Ethernet switches installed in your network that have been configured to use the Spanning Tree protocol. +-- DualNet - Both ports A and B are used as separate devices at the same + time. So if you have a dual port adapter, port A will show up as eth0 + and port B as eth1. Both ports can be used independend with distinct + IP addresses. + The preferred port setting is not used. Rlmt is turned off. + + NOTE: The modes CheckLocalPort and CheckSeg are meant to operate in configurations where a network path between the ports on one adapter exists. Especially, they are not designed to work where @@ -269,7 +276,7 @@ which you set the parameter (A or B). Large frames (also called jumbo frames) are now supported by the driver. This can result in a greatly improved throughput if -transferring large amounts of data. +transfering large amounts of data. To enable large frames, set the MTU (maximum transfer unit) of the interface to the value you wish (up to 9000). The command for this is: @@ -285,7 +292,7 @@ it will simply drop them. You can switch back to the standard ethernet frame size with: ifconfig eth0 mtu 1500 -To make this setting persistent, add a script with the 'ifconfig' +To make this setting persitent, add a script with the 'ifconfig' line to the system startup sequence (named something like "S99sk98lin" in /etc/rc.d/rc2.d). *** @@ -373,11 +380,27 @@ following information is available: (8) HISTORY =========== -VERSION 3.05 (In-Kernel version) +VERSION 4.02 (In-Kernel version) +New Features: +- Add Kernel 2.4 changes +Known limitations: +- None + +VERSION 4.01 (In-Kernel version) Problems fixed: -- Failed for multiple adapters in kernel 2.4.0 -New features: -- New versions of several common modules +- Full statistics support for DualNet mode +Known limitations: +- None + +VERSION 4.00 (In-Kernel version) +Problems fixed: +- Memory leak found +New Features: +- Proc filesystem integration +- DualNet functionality integrated +- Rlmt networks added +Known limitations: +- statistics partially incorrect in DualNet mode VERSION 3.04 (In-Kernel version) Problems fixed: @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 6 -EXTRAVERSION =-pre8 +EXTRAVERSION =-pre9 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff --git a/arch/alpha/boot/bootloader.lds b/arch/alpha/boot/bootloader.lds index b9f1c5cc8061..6643ae256c2f 100644 --- a/arch/alpha/boot/bootloader.lds +++ b/arch/alpha/boot/bootloader.lds @@ -6,7 +6,7 @@ SECTIONS .text : { *(.text) } _etext = .; PROVIDE (etext = .); - .rodata : { *(.rodata) } + .rodata : { *(.rodata) *(.rodata.*) } .data : { *(.data) CONSTRUCTORS } .got : { *(.got) } .sdata : { *(.sdata) } diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c index 91e99f573436..6e8056ad7023 100644 --- a/arch/alpha/kernel/irq_alpha.c +++ b/arch/alpha/kernel/irq_alpha.c @@ -18,6 +18,8 @@ unsigned long __irq_attempt[NR_IRQS]; #endif +extern unsigned long irq_err_count; + /* Hack minimum IPL during interrupt processing for broken hardware. */ #ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK int __min_ipl; diff --git a/arch/alpha/vmlinux.lds.in b/arch/alpha/vmlinux.lds.in index a153e5bd1ee1..da193ba5aa66 100644 --- a/arch/alpha/vmlinux.lds.in +++ b/arch/alpha/vmlinux.lds.in @@ -53,7 +53,7 @@ SECTIONS /* Global data */ _data = .; .data.cacheline_aligned : { *(.data.cacheline_aligned) } - .rodata : { *(.rodata) } + .rodata : { *(.rodata) *(.rodata.*) } .data : { *(.data) CONSTRUCTORS } .got : { *(.got) } .sdata : { *(.sdata) } diff --git a/arch/arm/boot/compressed/vmlinux.lds.in b/arch/arm/boot/compressed/vmlinux.lds.in index 8608996e91f1..6cd1348d868b 100644 --- a/arch/arm/boot/compressed/vmlinux.lds.in +++ b/arch/arm/boot/compressed/vmlinux.lds.in @@ -24,6 +24,7 @@ SECTIONS *(.fixup) *(.gnu.warning) *(.rodata) + *(.rodata.*) *(.glue_7) *(.glue_7t) input_data = .; diff --git a/arch/arm/vmlinux-armo.lds.in b/arch/arm/vmlinux-armo.lds.in index f42deb72c0a3..8bea493ceafa 100644 --- a/arch/arm/vmlinux-armo.lds.in +++ b/arch/arm/vmlinux-armo.lds.in @@ -47,6 +47,7 @@ SECTIONS *(.gnu.warning) *(.text.lock) /* out-of-line lock text */ *(.rodata) + *(.rodata.*) *(.glue_7) *(.glue_7t) *(.kstrtab) diff --git a/arch/arm/vmlinux-armv.lds.in b/arch/arm/vmlinux-armv.lds.in index 26089b83551e..5d555d41f789 100644 --- a/arch/arm/vmlinux-armv.lds.in +++ b/arch/arm/vmlinux-armv.lds.in @@ -42,6 +42,7 @@ SECTIONS *(.gnu.warning) *(.text.lock) /* out-of-line lock text */ *(.rodata) + *(.rodata.*) *(.glue_7) *(.glue_7t) *(.got) /* Global offset table */ diff --git a/arch/cris/boot/compressed/decompress.ld b/arch/cris/boot/compressed/decompress.ld index 24be54924970..0b0a14fe6177 100644 --- a/arch/cris/boot/compressed/decompress.ld +++ b/arch/cris/boot/compressed/decompress.ld @@ -13,6 +13,7 @@ SECTIONS _stext = . ; *(.text) *(.rodata) + *(.rodata.*) _etext = . ; } > dram .data : diff --git a/arch/cris/cris.ld b/arch/cris/cris.ld index 419167b8e28f..6d3187edcc05 100644 --- a/arch/cris/cris.ld +++ b/arch/cris/cris.ld @@ -24,7 +24,7 @@ SECTIONS *(.fixup) *(.text.__*) *(.rodata) - *(.rodata.__*) + *(.rodata.*) } . = ALIGN(4); /* Exception table */ diff --git a/arch/i386/boot/tools/build.c b/arch/i386/boot/tools/build.c index 2149dcf5130d..2edd0a4ec598 100644 --- a/arch/i386/boot/tools/build.c +++ b/arch/i386/boot/tools/build.c @@ -154,7 +154,7 @@ int main(int argc, char ** argv) if (sys_size > (is_big_kernel ? 0x28000 : DEF_SYSSIZE)) die("System is too big. Try using %smodules.", is_big_kernel ? "" : "bzImage or "); - if (sys_size > 0xffff) + if (sys_size > 0xefff) fprintf(stderr,"warning: kernel is too big for standalone boot " "from floppy\n"); while (sz > 0) { diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 35de35646dd7..822ae7407f64 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -374,6 +374,7 @@ CONFIG_NET_ETHERNET=y # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set # CONFIG_DEPCA is not set # CONFIG_HP100 is not set # CONFIG_NET_ISA is not set @@ -384,6 +385,8 @@ CONFIG_NET_PCI=y # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set # CONFIG_TULIP is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set # CONFIG_DE4X5 is not set # CONFIG_DGRS is not set # CONFIG_DM9102 is not set @@ -410,6 +413,7 @@ CONFIG_EEPRO100=y # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set # CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set @@ -538,6 +542,7 @@ CONFIG_AGP_VIA=y CONFIG_AGP_AMD=y CONFIG_AGP_SIS=y CONFIG_AGP_ALI=y +# CONFIG_AGP_SWORKS is not set CONFIG_DRM=y CONFIG_DRM_TDFX=y # CONFIG_DRM_GAMMA is not set @@ -595,7 +600,6 @@ CONFIG_DEVPTS_FS=y # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -656,6 +660,7 @@ CONFIG_SOUND_ES1371=y # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set # CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set # CONFIG_SOUND_OSS is not set # CONFIG_SOUND_TVMIXER is not set diff --git a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c index 022b4e5cdbbf..5ae7f060efc4 100644 --- a/arch/i386/kernel/bluesmoke.c +++ b/arch/i386/kernel/bluesmoke.c @@ -233,7 +233,7 @@ void __init mcheck_init(struct cpuinfo_x86 *c) } } -static void __init mcheck_disable(char *str, int *unused) +static int __init mcheck_disable(char *str) { mce_disabled = 1; return 1; diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index 4dbb196a9c1d..526a00e7461d 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -90,9 +90,6 @@ EXPORT_SYMBOL(__const_udelay); EXPORT_SYMBOL_NOVERS(__get_user_1); EXPORT_SYMBOL_NOVERS(__get_user_2); EXPORT_SYMBOL_NOVERS(__get_user_4); -EXPORT_SYMBOL_NOVERS(__put_user_1); -EXPORT_SYMBOL_NOVERS(__put_user_2); -EXPORT_SYMBOL_NOVERS(__put_user_4); EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strpbrk); diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index dc2823e4dced..74843f3e6479 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -8,7 +8,7 @@ L_TARGET = lib.a obj-y = checksum.o old-checksum.o delay.o \ - usercopy.o getuser.o putuser.o \ + usercopy.o getuser.o \ memcpy.o strstr.o obj-$(CONFIG_X86_USE_3DNOW) += mmx.o diff --git a/arch/i386/lib/putuser.S b/arch/i386/lib/putuser.S deleted file mode 100644 index ee56d83f779a..000000000000 --- a/arch/i386/lib/putuser.S +++ /dev/null @@ -1,71 +0,0 @@ -/* - * __put_user functions. - * - * (C) Copyright 1998 Linus Torvalds - * - * These functions have a non-standard call interface - * to make them more efficient. - */ - -/* - * __put_user_X - * - * Inputs: %eax contains the address - * %edx contains the value - * - * Outputs: %eax is error code (0 or -EFAULT) - * %ecx is corrupted (will contain "current_task"). - * - * These functions should not modify any other registers, - * as they get called from within inline assembly. - */ - -addr_limit = 12 - -.text -.align 4 -.globl __put_user_1 -__put_user_1: - movl %esp,%ecx - andl $0xffffe000,%ecx - cmpl addr_limit(%ecx),%eax - jae bad_put_user -1: movb %dl,(%eax) - xorl %eax,%eax - ret - -.align 4 -.globl __put_user_2 -__put_user_2: - addl $1,%eax - movl %esp,%ecx - jc bad_put_user - andl $0xffffe000,%ecx - cmpl addr_limit(%ecx),%eax - jae bad_put_user -2: movw %dx,-1(%eax) - xorl %eax,%eax - ret - -.align 4 -.globl __put_user_4 -__put_user_4: - addl $3,%eax - movl %esp,%ecx - jc bad_put_user - andl $0xffffe000,%ecx - cmpl addr_limit(%ecx),%eax - jae bad_put_user -3: movl %edx,-3(%eax) - xorl %eax,%eax - ret - -bad_put_user: - movl $-14,%eax - ret - -.section __ex_table,"a" - .long 1b,bad_put_user - .long 2b,bad_put_user - .long 3b,bad_put_user -.previous diff --git a/arch/i386/vmlinux.lds b/arch/i386/vmlinux.lds index 73dc2a25e374..ce14066f48f5 100644 --- a/arch/i386/vmlinux.lds +++ b/arch/i386/vmlinux.lds @@ -17,7 +17,7 @@ SECTIONS _etext = .; /* End of text section */ - .rodata : { *(.rodata) } + .rodata : { *(.rodata) *(.rodata.*) } .kstrtab : { *(.kstrtab) } . = ALIGN(16); /* Exception table */ diff --git a/arch/ia64/boot/bootloader.lds b/arch/ia64/boot/bootloader.lds index a7351840631d..69ae58531033 100644 --- a/arch/ia64/boot/bootloader.lds +++ b/arch/ia64/boot/bootloader.lds @@ -12,7 +12,7 @@ SECTIONS /* Global data */ _data = .; - .rodata : { *(.rodata) } + .rodata : { *(.rodata) *(.rodata.*) } .data : { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS } __gp = ALIGN (8) + 0x200000; .got : { *(.got.plt) *(.got) } diff --git a/arch/ia64/sn/fprom/fprom.lds b/arch/ia64/sn/fprom/fprom.lds index 8f416ec83e14..b57fd5cc2799 100644 --- a/arch/ia64/sn/fprom/fprom.lds +++ b/arch/ia64/sn/fprom/fprom.lds @@ -24,7 +24,7 @@ SECTIONS _data = .; .rodata : AT(ADDR(.rodata) - 0x0000000000000000 ) - { *(.rodata) } + { *(.rodata) *(.rodata.*) } .opd : AT(ADDR(.opd) - 0x0000000000000000 ) { *(.opd) } .data : AT(ADDR(.data) - 0x0000000000000000 ) diff --git a/arch/ia64/vmlinux.lds.S b/arch/ia64/vmlinux.lds.S index abef0063eae2..9064b6321972 100644 --- a/arch/ia64/vmlinux.lds.S +++ b/arch/ia64/vmlinux.lds.S @@ -83,7 +83,7 @@ SECTIONS ia64_unw_end = .; .rodata : AT(ADDR(.rodata) - PAGE_OFFSET) - { *(.rodata) } + { *(.rodata) *(.rodata.*) } .kstrtab : AT(ADDR(.kstrtab) - PAGE_OFFSET) { *(.kstrtab) } .opd : AT(ADDR(.opd) - PAGE_OFFSET) diff --git a/arch/m68k/vmlinux-sun3.lds b/arch/m68k/vmlinux-sun3.lds index 92ca61233a8d..4848631fe038 100644 --- a/arch/m68k/vmlinux-sun3.lds +++ b/arch/m68k/vmlinux-sun3.lds @@ -20,6 +20,7 @@ SECTIONS .data : { /* Data */ *(.rodata) + *(.rodata.*) *(.data) CONSTRUCTORS . = ALIGN(16); /* Exception table */ diff --git a/arch/m68k/vmlinux.lds b/arch/m68k/vmlinux.lds index 5058d8d02ef3..f24a564db1f2 100644 --- a/arch/m68k/vmlinux.lds +++ b/arch/m68k/vmlinux.lds @@ -12,7 +12,7 @@ SECTIONS *(.text.lock) /* out-of-line lock text */ *(.gnu.warning) } = 0x4e75 - .rodata : { *(.rodata) } + .rodata : { *(.rodata) *(.rodata.*) } .kstrtab : { *(.kstrtab) } . = ALIGN(16); /* Exception table */ diff --git a/arch/mips/Makefile b/arch/mips/Makefile index f0cfda414749..a3df4dbc7d8b 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -17,10 +17,8 @@ # ifdef CONFIG_CPU_LITTLE_ENDIAN tool-prefix = mipsel-linux- -output-format = elf32-littlemips else tool-prefix = mips-linux- -output-format = elf32-bigmips endif ifdef CONFIG_CROSSCOMPILE @@ -51,9 +49,6 @@ endif ifdef CONFIG_CPU_R3000 GCCFLAGS += -mcpu=r3000 -mips1 endif -ifdef CONFIG_CPU_R3912 -GCCFLAGS += -mcpu=r3000 -mips1 -endif ifdef CONFIG_CPU_R6000 GCCFLAGS += -mcpu=r6000 -mips2 -Wa,--trap endif @@ -67,22 +62,19 @@ ifdef CONFIG_CPU_MIPS32 GCCFLAGS += -mcpu=r4600 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_R5000 -GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r5000 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_R5432 -GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r5000 -mips2 -Wa,--trap endif ifdef CONFIG_CPU_NEVADA -GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap -mmad +GCCFLAGS += -mcpu=r5000 -mips2 -Wa,--trap -mmad endif ifdef CONFIG_CPU_RM7000 -GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap -endif -ifdef CONFIG_CPU_R8000 -GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap +GCCFLAGS += -mcpu=r5000 -mips2 -Wa,--trap endif -ifdef CONFIG_CPU_R10000 -GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap +ifdef CONFIG_CPU_SB1 +GCCFLAGS += -mcpu=sb1 -mips2 -Wa,--trap endif ifdef CONFIG_MIPS_FPU_EMULATOR @@ -90,14 +82,11 @@ CORE_FILES +=arch/mips/math-emu/fpu_emulator.o SUBDIRS +=arch/mips/math-emu endif -# -# The pipe options is bad for my low-mem machine -# Uncomment this if you want this. -# GCCFLAGS += -pipe CFLAGS := -I $(TOPDIR)/include/asm/gcc $(CFLAGS) $(GCCFLAGS) AFLAGS += $(GCCFLAGS) +ASFLAGS += $(GCCFLAGS) # # Board-dependent options and extra files @@ -178,15 +167,6 @@ LOADADDR += 0x80080000 endif # -# Orion Board -# -ifdef CONFIG_ORION -LIBS += arch/mips/orion/orionkern.a -SUBDIRS += arch/mips/orion -LINKSCRIPT = arch/mips/orion/ld.script.orion -endif - -# # # NEC DDB Vrc-5476 # @@ -197,6 +177,17 @@ LOADADDR += 0x80080000 endif # +# +# NEC DDB Vrc-5477 +# +ifdef CONFIG_DDB5477 +SUBDIRS += arch/mips/ddb5xxx/common arch/mips/ddb5xxx/ddb5477 +LIBS += arch/mips/ddb5xxx/common/ddb5xxx.o \ + arch/mips/ddb5xxx/ddb5477/ddb5477.o +LOADADDR += 0x80080000 +endif + +# # Galileo EV64120 Board # ifdef CONFIG_MIPS_EV64120 @@ -218,7 +209,9 @@ endif # Momentum Ocelot board # ifdef CONFIG_MOMENCO_OCELOT -LIBS += arch/mips/gt64120/common/gt64120.o arch/mips/gt64120/momenco_ocelot/momenco_ocelot.o +# The Ocelot setup.o must be linked early - it does the ioremap() for the +# mips_io_port_base. +CORE_FILES += arch/mips/gt64120/common/gt64120.o arch/mips/gt64120/momenco_ocelot/momenco_ocelot.o SUBDIRS += arch/mips/gt64120/common arch/mips/gt64120/momenco_ocelot LOADADDR += 0x80100000 endif @@ -227,9 +220,8 @@ endif # Philips Nino # ifdef CONFIG_NINO -CORE_FILES += arch/mips/philips/nino/nino.o \ - arch/mips/philips/drivers/drivers.o -SUBDIRS += arch/mips/philips/nino arch/mips/philips/drivers +CORE_FILES += arch/mips/philips/nino/nino.o +SUBDIRS += arch/mips/philips/nino LOADADDR += 0x80000000 endif @@ -252,8 +244,7 @@ endif vmlinux: arch/$(ARCH)/ld.script arch/$(ARCH)/ld.script: arch/$(ARCH)/ld.script.in arch/$(ARCH)/Makefile - sed -e 's/@@OUTPUT_FORMAT@@/$(output-format)/' \ - -e 's/@@LOADADDR@@/$(LOADADDR)/' <$< >$@ + sed -e 's/@@LOADADDR@@/$(LOADADDR)/' <$< >$@ LINKFLAGS += -T arch/$(ARCH)/ld.script HEAD := arch/mips/kernel/head.o arch/mips/kernel/init_task.o @@ -271,13 +262,6 @@ balo: vmlinux endif -ifdef CONFIG_ORION -ORIONBOOT = $(MAKE) -C arch/$(ARCH)/orion - -orionboot: - $(ORIONBOOT) orionboot -endif - ifdef CONFIG_MIPS_EV64120 GALILEOBOOT = $(MAKE) -C arch/$(ARCH)/galileo-boards/ev64120 diff --git a/arch/mips/arc/cmdline.c b/arch/mips/arc/cmdline.c index e6f348384d1a..54943c3d4bf3 100644 --- a/arch/mips/arc/cmdline.c +++ b/arch/mips/arc/cmdline.c @@ -25,10 +25,49 @@ static char *ignored[] = { "SystemPartition=", "OSLoader=", "OSLoadPartition=", - "OSLoadFilename=" + "OSLoadFilename=", + "OSLoadOptions=" }; #define NENTS(foo) ((sizeof((foo)) / (sizeof((foo[0]))))) +static char *used_arc[][2] = { + { "OSLoadPartition=", "root=" }, + { "OSLoadOptions=", "" } +}; + +static char * __init move_firmware_args(char* cp) +{ + char *s; + int actr, i; + + actr = 1; /* Always ignore argv[0] */ + + while (actr < prom_argc) { + for(i = 0; i < NENTS(used_arc); i++) { + int len = strlen(used_arc[i][0]); + + if(!strncmp(prom_argv[actr], used_arc[i][0], len)) { + /* Ok, we want it. First append the replacement... */ + strcat(cp, used_arc[i][1]); + cp += strlen(used_arc[i][1]); + /* ... and now the argument */ + s = strstr(prom_argv[actr], "="); + if(s) { + s++; + strcpy(cp, s); + cp += strlen(s); + } + *cp++ = ' '; + break; + } + } + actr++; + } + + return cp; +} + + void __init prom_init_cmdline(void) { char *cp; @@ -37,8 +76,14 @@ void __init prom_init_cmdline(void) actr = 1; /* Always ignore argv[0] */ cp = &(arcs_cmdline[0]); - while(actr < prom_argc) { - for(i = 0; i < NENTS(ignored); i++) { + /* + * Move ARC variables to the beginning to make sure they can be + * overridden by later arguments. + */ + cp = move_firmware_args(cp); + + while (actr < prom_argc) { + for (i = 0; i < NENTS(ignored); i++) { int len = strlen(ignored[i]); if(!strncmp(prom_argv[actr], ignored[i], len)) diff --git a/arch/mips/arc/console.c b/arch/mips/arc/console.c index 8138dbd00d83..3b012c614e03 100644 --- a/arch/mips/arc/console.c +++ b/arch/mips/arc/console.c @@ -15,10 +15,6 @@ #include <linux/kdev_t.h> #include <linux/major.h> -#ifdef CONFIG_ARC_CONSOLE -#define __init -#endif - /* * IP22 boardcache is not compatible with board caches. Thus we disable it * during romvec action. Since r4xx0.c is always compiled and linked with your @@ -29,7 +25,7 @@ * in some way. You should be careful with them. */ -void __init prom_putchar(char c) +void prom_putchar(char c) { long cnt; char it = c; @@ -53,7 +49,7 @@ char __init prom_getchar(void) static char ppbuf[1024]; -void __init prom_printf(char *fmt, ...) +void prom_printf(char *fmt, ...) { va_list args; char ch, *bptr; @@ -72,28 +68,3 @@ void __init prom_printf(char *fmt, ...) } va_end(args); } - -static void -arc_console_write(struct console *con, const char *s, unsigned n) -{ - prom_printf("%s", s); -} - -static kdev_t -arc_console_dev(struct console *c) -{ - return MKDEV(TTY_MAJOR, 64 + c->index); -} - -static struct console arc_prom_console = { - name: "prom", - write: arc_console_write, - device: arc_console_dev, - flags: CON_PRINTBUFFER, - index: -1, -}; - -__init void arc_setup_console(void) -{ - register_console(&arc_prom_console); -} diff --git a/arch/mips/arc/identify.c b/arch/mips/arc/identify.c index a2ee29fb4fed..8fef325076ff 100644 --- a/arch/mips/arc/identify.c +++ b/arch/mips/arc/identify.c @@ -36,7 +36,7 @@ static struct smatch *__init string_to_mach(char *s) { int i; - for (i = 0; i < sizeof(mach_table); i++) { + for (i = 0; i < (sizeof(mach_table) / sizeof (mach_table[0])); i++) { if (!strcmp(s, mach_table[i].name)) return &mach_table[i]; } diff --git a/arch/mips/arc/memory.c b/arch/mips/arc/memory.c index 3f41f74ce4ae..d8f22201def4 100644 --- a/arch/mips/arc/memory.c +++ b/arch/mips/arc/memory.c @@ -32,7 +32,7 @@ static char *arcs_mtypes[8] = { "Free/Contig RAM", "Generic Free RAM", "Bad Memory", - "Standlong Program Pages", + "Standalone Program Pages", "ARCS Temp Storage Area", "ARCS Permanent Storage Area" }; diff --git a/arch/mips/arc/misc.c b/arch/mips/arc/misc.c index 5a7edb7748c0..95a4ef05d54f 100644 --- a/arch/mips/arc/misc.c +++ b/arch/mips/arc/misc.c @@ -56,7 +56,7 @@ void prom_reboot(void) romvec->reboot(); } -void prom_imode(void) +void ArcEnterInteractiveMode(void) { bc_disable(); cli(); diff --git a/arch/mips/baget/ld.script.balo b/arch/mips/baget/ld.script.balo index e6fd192dbe99..e20e4d066ffa 100644 --- a/arch/mips/baget/ld.script.balo +++ b/arch/mips/baget/ld.script.balo @@ -31,6 +31,7 @@ SECTIONS _ftext = . ; *(.text) *(.rodata) + *(.rodata.*) *(.rodata1) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) diff --git a/arch/mips/boot/mkboot.c b/arch/mips/boot/mkboot.c index 35612d2483fa..9e587eb1a935 100644 --- a/arch/mips/boot/mkboot.c +++ b/arch/mips/boot/mkboot.c @@ -5,7 +5,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996 by Ralf Baechle + * Copyright (C) 1996, 2001 by Ralf Baechle * * This file is written in plain Kernighan & Ritchie C as it has to run * on all crosscompile hosts no matter how braindead. This code might @@ -80,7 +80,6 @@ typedef struct * Acceptable machine type in e_machine. */ #define EM_MIPS 8 /* MIPS R3000 big-endian */ -#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ /* * The type of ELF file we accept. @@ -462,7 +461,7 @@ main(argc, argv) fprintf(stderr, "Input file isn't a executable.\n"); exit(1); } - if(eh.e_machine != EM_MIPS && eh.e_machine != EM_MIPS_RS4_BE) { + if(eh.e_machine != EM_MIPS) { fprintf(stderr, "Input file isn't a MIPS executable.\n"); exit(1); } diff --git a/arch/mips/config.in b/arch/mips/config.in index a1bc680fa96f..6f6fbb8ad5a1 100644 --- a/arch/mips/config.in +++ b/arch/mips/config.in @@ -2,6 +2,9 @@ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # +define_bool CONFIG_MIPS y +define_bool CONFIG_SMP n + mainmenu_name "Linux Kernel Configuration" mainmenu_option next_comment @@ -15,18 +18,55 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'Support for Acer PICA 1 chipset' CONFIG_ACER_PICA_61 bool 'Support for Algorithmics P4032 (EXPERIMENTAL)' CONFIG_ALGOR_P4032 bool 'Support for BAGET MIPS series (EXPERIMENTAL)' CONFIG_BAGET_MIPS - bool 'Support for Cobalt Server' CONFIG_COBALT_MICRO_SERVER - if [ "$CONFIG_COBALT_MICRO_SERVER" = "y" ]; then - bool ' Support for 2800' CONFIG_COBALT_28 - fi bool 'Support for DECstations (EXPERIMENTAL)' CONFIG_DECSTATION bool 'Support for NEC DDB Vrc-5074 (EXPERIMENTAL)' CONFIG_DDB5074 - bool 'Support for Galileo Evaluation board or CoSine Orion' CONFIG_ORION + bool 'Support for Galileo EV96100 Evaluation board' CONFIG_MIPS_EV96100 + bool 'Support for Galileo EV64120 Evaluation board' CONFIG_MIPS_EV64120 + if [ "$CONFIG_MIPS_EV64120" = "y" ]; then + bool 'Enable Second PCI (PCI1)' CONFIG_EVB_PCI1 + choice 'Galileo Chip Clock' \ + "75 CONFIG_SYSCLK_75\ + 83.3 CONFIG_SYSCLK_83\ + 100 CONFIG_SYSCLK_100" CONFIG_SYSCLK_83 + fi + bool 'Support for MIPS Atlas board' CONFIG_MIPS_ATLAS + bool 'Support for MIPS Malta board' CONFIG_MIPS_MALTA + bool 'Support for Philips Nino (EXPERIMENTAL)' CONFIG_NINO + if [ "$CONFIG_NINO" = "y" ]; then + choice 'Nino Model Number' \ + "Model-300/301/302/319 CONFIG_NINO_4MB \ + Model-200/210/312/320/325/350/390 CONFIG_NINO_8MB \ + Model-500/510 CONFIG_NINO_16MB" CONFIG_NINO_8MB + fi fi bool 'Support for Mips Magnum 4000' CONFIG_MIPS_MAGNUM_4000 +bool 'Support for Momentum Ocelot board' CONFIG_MOMENCO_OCELOT +bool 'Support for NEC DDB Vrc-5476' CONFIG_DDB5476 +bool 'Support for NEC DDB Vrc-5477' CONFIG_DDB5477 bool 'Support for Olivetti M700-10' CONFIG_OLIVETTI_M700 bool 'Support for SGI IP22' CONFIG_SGI_IP22 bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI +bool 'Support for ITE 8172G board' CONFIG_MIPS_ITE8172 + if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then + bool ' Support for older IT8172 (Rev C)' CONFIG_IT8172_REVC + bool ' Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD + if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then + define_bool CONFIG_IT8172_CIR y + else + bool ' Enable PS2 Keyboard Support ' CONFIG_PC_KEYB + fi + bool ' Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0 + bool ' Enable Smart Card Reader 1 Support ' CONFIG_IT8172_SCR1 + fi + bool 'Support for Globespan IVR board' CONFIG_MIPS_IVR + if [ "$CONFIG_MIPS_IVR" = "y" ]; then + bool ' Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD + if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then + define_bool CONFIG_IT8172_CIR y + fi + bool ' Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0 + fi +bool 'Support for Alchemy Semi PB1000 board' CONFIG_MIPS_PB1000 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n @@ -35,54 +75,127 @@ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n # Select some configuration options automatically for certain systems. # unset CONFIG_ARC32 +unset CONFIG_BOARD_SCACHE +unset CONFIG_HAVE_STD_PC_SERIAL_PORT +unset CONFIG_I8259 unset CONFIG_ISA -unset CONFIG_EISA unset CONFIG_PCI unset CONFIG_MIPS_JAZZ +unset CONFIG_SWAP_IO_SPACE unset CONFIG_VIDEO_G364 unset CONFIG_PC_KEYB define_bool CONFIG_MCA n define_bool CONFIG_SBUS n +if [ "$CONFIG_MIPS_EV96100" = "y" ]; then + define_bool CONFIG_PCI y + define_bool CONFIG_MIPS_GT96100 y + define_bool CONFIG_SWAP_IO_SPACE y +fi +if [ "$CONFIG_MIPS_EV64120" = "y" ]; then + define_bool CONFIG_PCI y + define_bool CONFIG_ISA n + define_bool CONFIG_MIPS_GT64120 y + define_bool CONFIG_OLD_TIME_C y +fi + if [ "$CONFIG_ALGOR_P4032" = "y" ]; then define_bool CONFIG_PCI y + define_bool CONFIG_OLD_TIME_C y fi if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \ "$CONFIG_OLIVETTI_M700" = "y" ]; then define_bool CONFIG_ARC32 y + define_bool CONFIG_I8259 y define_bool CONFIG_ISA y define_bool CONFIG_FB y define_bool CONFIG_FB_G364 y define_bool CONFIG_MIPS_JAZZ y define_bool CONFIG_PC_KEYB y + define_bool CONFIG_OLD_TIME_C y fi if [ "$CONFIG_ACER_PICA_61" = "y" ]; then define_bool CONFIG_ARC32 y + define_bool CONFIG_I8259 y define_bool CONFIG_ISA y define_bool CONFIG_MIPS_JAZZ y define_bool CONFIG_PC_KEYB y + define_bool CONFIG_ROTTEN_IRQ y + define_bool CONFIG_OLD_TIME_C y +fi +if [ "$CONFIG_MIPS_ATLAS" = "y" ]; then + define_bool CONFIG_PCI y + define_bool CONFIG_SWAP_IO_SPACE y +fi +if [ "$CONFIG_MIPS_MALTA" = "y" ]; then + define_bool CONFIG_I8259 y + define_bool CONFIG_PCI y + define_bool CONFIG_HAVE_STD_PC_SERIAL_PORT y + define_bool CONFIG_SWAP_IO_SPACE y fi -if [ "$CONFIG_COBALT_MICRO_SERVER" = "y" ]; then - define_bool CONFIG_COBALT_27 y - define_bool CONFIG_COBALT_LCD y - define_bool CONFIG_COBALT_SERIAL y +if [ "$CONFIG_MOMENCO_OCELOT" = "y" ]; then define_bool CONFIG_PCI y + define_bool CONFIG_SYSCLK_100 y + define_bool CONFIG_SWAP_IO_SPACE y + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_OLD_TIME_C y fi if [ "$CONFIG_SGI_IP22" = "y" ]; then define_bool CONFIG_ARC32 y + define_bool CONFIG_BOARD_SCACHE y define_bool CONFIG_PC_KEYB y define_bool CONFIG_SGI y + define_bool CONFIG_NEW_IRQ y + define_bool CONFIG_OLD_TIME_C y fi if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then define_bool CONFIG_ARC32 y + define_bool CONFIG_I8259 y + define_bool CONFIG_ISA y + define_bool CONFIG_PC_KEYB y define_bool CONFIG_PCI y + define_bool CONFIG_ROTTEN_IRQ y + define_bool CONFIG_OLD_TIME_C y +fi +if [ "$CONFIG_DDB5074" = "y"]; then + define_bool CONFIG_I8259 y define_bool CONFIG_ISA y + define_bool CONFIG_PCI y define_bool CONFIG_PC_KEYB y + define_bool CONFIG_ROTTEN_IRQ y + define_bool CONFIG_HAVE_STD_PC_SERIAL_PORT y + define_bool CONFIG_OLD_TIME_C y fi -if [ "$CONFIG_DDB5074" = "y" ]; then +if [ "$CONFIG_DDB5476" = "y" ]; then + define_bool CONFIG_I8259 y define_bool CONFIG_ISA y define_bool CONFIG_PCI y + define_bool CONFIG_PC_KEYB y + define_bool CONFIG_ROTTEN_IRQ y + define_bool CONFIG_HAVE_STD_PC_SERIAL_PORT y + define_bool CONFIG_NEW_TIME_C y +fi +if [ "$CONFIG_DDB5477" = "y" ]; then + define_bool CONFIG_CPU_LITTLE_ENDIAN y + define_bool CONFIG_PCI y + define_bool CONFIG_NEW_TIME_C y + define_bool CONFIG_NEW_IRQ y +fi +if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then + define_bool CONFIG_PCI y + define_bool CONFIG_IT8712 y + define_bool CONFIG_PC_KEYB y +fi +if [ "$CONFIG_MIPS_IVR" = "y" ]; then + define_bool CONFIG_PCI y +fi +if [ "$CONFIG_MIPS_PB1000" = "y" ]; then + define_bool CONFIG_MIPS_AU1000 y + define_bool CONFIG_NEW_IRQ y +fi +if [ "$CONFIG_NINO" = "y" ]; then + define_bool CONFIG_PC_KEYB y fi if [ "$CONFIG_ISA" != "y" ]; then @@ -95,6 +208,10 @@ fi if [ "$CONFIG_PCI" != "y" ]; then define_bool CONFIG_PCI n fi + +if [ "$CONFIG_I8259" != "y" ]; then + define_bool CONFIG_I8259 n +fi endmenu mainmenu_option next_comment @@ -115,9 +232,12 @@ choice 'CPU type' \ R4300 CONFIG_CPU_R4300 \ R4x00 CONFIG_CPU_R4X00 \ R5000 CONFIG_CPU_R5000 \ - R56x0 CONFIG_CPU_NEVADA \ - R8000 CONFIG_CPU_R8000 \ - R10000 CONFIG_CPU_R10000" R4x00 + R5432 CONFIG_CPU_R5432 \ + RM7000 CONFIG_CPU_RM7000 \ + R52xx CONFIG_CPU_NEVADA \ + R10000 CONFIG_CPU_R10000 \ + SB1 CONFIG_CPU_SB1 \ + MIPS32 CONFIG_CPU_MIPS32" R4x00 bool 'Override CPU Options' CONFIG_CPU_ADVANCED @@ -134,19 +254,23 @@ else define_bool CONFIG_CPU_HAS_WB n fi else - define_bool CONFIG_CPU_HAS_LLSC y - define_bool CONFIG_CPU_HAS_WB n + define_bool CONFIG_CPU_HAS_LLSC y + define_bool CONFIG_CPU_HAS_WB n fi fi endmenu mainmenu_option next_comment comment 'General setup' -if [ "$CONFIG_DECSTATION" = "y" -o "$CONFIG_DDB5074" = "y" ]; then +if [ "$CONFIG_DECSTATION" = "y" -o \ + "$CONFIG_DDB5074" = "y" -o \ + "$CONFIG_DDB5476" = "y" -o \ + "$CONFIG_NINO" = "y" ]; then define_bool CONFIG_CPU_LITTLE_ENDIAN y else bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN fi +bool 'Kernel floating-point emulation' CONFIG_MIPS_FPU_EMULATOR if [ "$CONFIG_PROC_FS" = "y" ]; then define_bool CONFIG_KCORE_ELF y @@ -158,22 +282,30 @@ if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then bool 'Include forward keyboard' CONFIG_FORWARD_KEYBOARD fi +if [ "$CONFIG_ARC32" = "y" ]; then + bool 'ARC console support' CONFIG_ARC_CONSOLE +fi + define_bool CONFIG_BINFMT_AOUT n define_bool CONFIG_BINFMT_ELF y tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC bool 'Networking support' CONFIG_NET -if [ "$CONFIG_PCI" = "y" ]; then - source drivers/pci/Config.in +source drivers/pci/Config.in + +bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG + +if [ "$CONFIG_HOTPLUG" = "y" ] ; then + source drivers/pcmcia/Config.in +else + define_bool CONFIG_PCMCIA n fi bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL -source drivers/parport/Config.in - if [ "$CONFIG_DECSTATION" = "y" ]; then bool 'TURBOchannel support' CONFIG_TC # if [ "$CONFIG_TC" = "y" ]; then @@ -186,14 +318,10 @@ if [ "$CONFIG_ISA" = "y" ]; then source drivers/pnp/Config.in fi -if [ "$CONFIG_HOTPLUG" = "y" ] ; then - source drivers/pcmcia/Config.in -else - define_bool CONFIG_PCMCIA n -fi - source drivers/mtd/Config.in +source drivers/parport/Config.in + source drivers/block/Config.in source drivers/md/Config.in @@ -202,10 +330,7 @@ if [ "$CONFIG_NET" = "y" ]; then source net/Config.in fi -if [ "$CONFIG_DECSTATION" != "y" -a \ - "$CONFIG_SGI_IP22" != "y" ]; then - source drivers/telephony/Config.in -fi +source drivers/telephony/Config.in if [ "$CONFIG_SGI_IP22" != "y" -a \ "$CONFIG_DECSTATION" != "y" ]; then @@ -236,7 +361,7 @@ endmenu if [ "$CONFIG_DECSTATION" != "y" -a \ "$CONFIG_SGI_IP22" != "y" ]; then - source drivers/i2o/Config.in + source drivers/message/i2o/Config.in fi if [ "$CONFIG_NET" = "y" ]; then @@ -245,69 +370,40 @@ if [ "$CONFIG_NET" = "y" ]; then bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then - - if [ "$CONFIG_SGI_IP22" != "y" -a \ - "$CONFIG_DECSTATION" != "y" -a \ - "$CONFIG_BAGET_MIPS" != "y" ]; then - - source drivers/net/Config.in - - if [ "$CONFIG_ATM" = "y" ]; then - source drivers/atm/Config.in - fi - else - tristate 'Dummy net driver support' CONFIG_DUMMY - tristate 'SLIP (serial line) support' CONFIG_SLIP - if [ "$CONFIG_SLIP" != "n" ]; then - bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED - bool ' Keepalive and linefill' CONFIG_SLIP_SMART - fi - tristate 'PPP (point-to-point) support' CONFIG_PPP - if [ ! "$CONFIG_PPP" = "n" ]; then - comment 'CCP compressors for PPP are only built as modules.' - fi - if [ "$CONFIG_SGI_IP22" = "y" ]; then - bool 'SGI Seeq ethernet controller support' CONFIG_SGISEEQ - fi - if [ "$CONFIG_DECSTATION" = "y" ]; then - bool 'DEC LANCE ethernet controller support' CONFIG_DECLANCE - fi - if [ "$CONFIG_BAGET_MIPS" = "y" ]; then - tristate 'Baget AMD LANCE support' CONFIG_BAGETLANCE - fi + source drivers/net/Config.in + if [ "$CONFIG_ATM" = "y" ]; then + source drivers/atm/Config.in fi fi endmenu fi -if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" ]; then - mainmenu_option next_comment - comment 'ISDN subsystem' - - if [ "$CONFIG_NET" != "n" ]; then - tristate 'ISDN support' CONFIG_ISDN - if [ "$CONFIG_ISDN" != "n" ]; then - source drivers/isdn/Config.in - fi - fi - endmenu +source net/ax25/Config.in - mainmenu_option next_comment - comment 'Old CD-ROM drivers (not SCSI, not IDE)' +source net/irda/Config.in - bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI - if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then - source drivers/cdrom/Config.in +mainmenu_option next_comment +comment 'ISDN subsystem' +if [ "$CONFIG_NET" != "n" ]; then + tristate 'ISDN support' CONFIG_ISDN + if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in fi - endmenu fi +endmenu -if [ "$CONFIG_DECSTATION" != "y" -a \ - "$CONFIG_SGI_IP22" != "y" ]; then - source drivers/char/Config.in +mainmenu_option next_comment +comment 'Old CD-ROM drivers (not SCSI, not IDE)' - source drivers/media/Config.in +bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI +if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then + source drivers/cdrom/Config.in fi +endmenu + +source drivers/char/Config.in + +source drivers/media/Config.in if [ "$CONFIG_DECSTATION" = "y" ]; then mainmenu_option next_comment @@ -332,9 +428,7 @@ if [ "$CONFIG_DECSTATION" = "y" ]; then # if [ "$CONFIG_ACCESSBUS" = "y" ]; then # bool 'MAXINE Access.Bus mouse (VSXXX-BB/GB) support' CONFIG_DTOP_MOUSE # fi - bool 'Enhanced Real Time Clock Support' CONFIG_MIPS_RTC - - define_tristate CONFIG_RTC $CONFIG_MIPS_RTC + bool 'Enhanced Real Time Clock Support' CONFIG_RTC endmenu fi @@ -351,7 +445,10 @@ if [ "$CONFIG_SGI_IP22" = "y" ]; then else define_bool CONFIG_FONT_8x16 y fi - bool 'SGI PROM Console Support' CONFIG_SGI_PROM_CONSOLE + fi + bool 'PS/2 mouse support' CONFIG_PSMOUSE + if [ "$CONFIG_PSMOUSE" != "n" ]; then + define_bool CONFIG_MOUSE y fi bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then @@ -364,13 +461,12 @@ source fs/Config.in if [ "$CONFIG_VT" = "y" ]; then mainmenu_option next_comment - comment 'Console drivers' - if [ "$CONFIG_DECSTATION" != "y" ]; then - bool 'VGA text console' CONFIG_VGA_CONSOLE - fi - bool 'Support for frame buffer devices' CONFIG_FB + bool 'VGA text console' CONFIG_VGA_CONSOLE + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE source drivers/video/Config.in + fi endmenu fi @@ -399,8 +495,15 @@ bool 'Are you using a crosscompiler' CONFIG_CROSSCOMPILE if [ "$CONFIG_MODULES" = "y" ]; then bool ' Build fp execption handler module' CONFIG_MIPS_FPE_MODULE fi -if [ "$CONFIG_SERIAL" = "y" ]; then +if [ "$CONFIG_SERIAL" = "y" -o "$CONFIG_AU1000_UART" = "y" ]; then bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG + dep_bool 'Console output to GDB' CONFIG_GDB_CONSOLE $CONFIG_REMOTE_DEBUG +fi +if [ "$CONFIG_SERIAL" = "y" ]; then + bool 'Low-level debugging' CONFIG_LL_DEBUG fi bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +if [ "$CONFIG_SMP" != "y" ]; then + bool 'Run uncached' CONFIG_MIPS_UNCACHED +fi endmenu diff --git a/arch/mips/dec/boot/ld.ecoff b/arch/mips/dec/boot/ld.ecoff index 8298ffae87ca..aaa633dfb5f7 100644 --- a/arch/mips/dec/boot/ld.ecoff +++ b/arch/mips/dec/boot/ld.ecoff @@ -13,7 +13,7 @@ SECTIONS } .rdata : { - *(.rodata .rdata) + *(.rodata .rodata.* .rdata) } .data : { diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index d140184a6379..0048aee9667b 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -6,93 +6,58 @@ # unless it's something special (ie not a .c file). # +.S.s: + $(CPP) $(AFLAGS) $< -o $@ .S.o: - $(CC) $(CFLAGS) -c $< -o $*.o + $(CC) $(AFLAGS) -c $< -o $@ + +EXTRA_AFLAGS = -mips3 -mcpu=r4000 all: kernel.o head.o init_task.o -EXTRA_ASFLAGS = -mips3 -mcpu=r4000 + O_TARGET := kernel.o -O_OBJS := branch.o process.o signal.o entry.o traps.o ptrace.o vm86.o \ - ioport.o reset.o semaphore.o setup.o syscall.o sysmips.o ipc.o \ - scall_o32.o softfp.o unaligned.o -OX_OBJS := mips_ksyms.o + +obj-y += branch.o process.o signal.o entry.o \ + traps.o ptrace.o vm86.o ioport.o reset.o \ + semaphore.o setup.o syscall.o sysmips.o \ + ipc.o scall_o32.o unaligned.o +obj-$(CONFIG_MODULES) += mips_ksyms.o ifdef CONFIG_CPU_R3000 -O_OBJS += r2300_misc.o r2300_fpu.o r2300_switch.o +obj-y += r2300_misc.o r2300_fpu.o r2300_switch.o else -O_OBJS += r4k_misc.o r4k_switch.o +obj-y += r4k_misc.o r4k_switch.o ifdef CONFIG_CPU_R6000 -O_OBJS += r6000_fpu.o +obj-y += r6000_fpu.o else -O_OBJS += r4k_fpu.o -endif +obj-y += r4k_fpu.o endif - -ifdef CONFIG_MIPS_FPE_MODULE -M_OBJS += fpe.o -endif - -# -# SGIs have very different interrupt/timer hardware. -# -ifndef CONFIG_DECSTATION - ifndef CONFIG_BAGET_MIPS - O_OBJS += time.o - ifndef CONFIG_SGI_IP22 - ifndef CONFIG_ORION - OX_OBJS += irq.o - endif - endif - endif endif -# -# Do we want to be able to execute IRIX elf binaries? -# -ifdef CONFIG_BINFMT_IRIX -O_OBJS += irixelf.o irixioctl.o irixsig.o sysirix.o irixinv.o +obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_MIPS_FPE_MODULE) += fpe.o +ifndef CONFIG_MIPS_FPU_EMULATOR + obj-y += softfp.o endif -# -# Kernel debugging -# -ifdef CONFIG_REMOTE_DEBUG -O_OBJS += gdb-low.o gdb-stub.o -endif +# Old style irq support, going to die in 2.5. +export-objs += old-irq.o +obj-$(CONFIG_NEW_IRQ) += irq.o +obj-$(CONFIG_ROTTEN_IRQ) += old-irq.o -# -# Depending from some other kernel option -# -ifdef CONFIG_PROC_FS -O_OBJS += proc.o -endif +# transition from old time.c to new time.c +# some boards uses old-time.c, some use time.c, and some use their own ones +export-objs += old-time.o time.o +obj-$(CONFIG_OLD_TIME_C) += old-time.o +obj-$(CONFIG_NEW_TIME_C) += time.o -# -# Since we add the same object files to O_OBJS for different configurations. -# O_OBJS might contain duplicate files. We correct this by filtering out -# duplicate files. Just to avoid users having to know about all the -# compatibility stuff between various boards and boards. -# -O_OBJS := $(sort $(O_OBJS)) +obj-$(CONFIG_BINFMT_IRIX) += irixelf.o irixioctl.o irixsig.o sysirix.o \ + irixinv.o +obj-$(CONFIG_REMOTE_DEBUG) += gdb-low.o gdb-stub.o +obj-$(CONFIG_PCI) += pci-dma.o +obj-$(CONFIG_PROC_FS) += proc.o entry.o: entry.S - head.o: head.S -#r4k_switch.o: r4k_switch.S -# -#r4k_misc.o: r4k_misc.S -# -#r4k_fpu.o: r4k_fpu.S -# -#r2300_switch.o: r2300_switch.S -# -#r2300_misc.o: r2300_misc.S -# -#r2300_fpu.o: r2300_fpu.S -# -#r6000_fpu.o: r6000_fpu.S - -clean: - include $(TOPDIR)/Rules.make diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index bc56db51bc07..8232e9364be4 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -12,6 +12,7 @@ #include <linux/config.h> #include <linux/sys.h> +#include <asm/addrspace.h> #include <asm/asm.h> #include <asm/current.h> #include <asm/errno.h> @@ -43,12 +44,17 @@ reschedule: jal schedule EXPORT(ret_from_sys_call) EXPORT(ret_from_irq) .type ret_from_irq,@function - lw t0, irq_stat # softirq_active - lw t1, irq_stat+4 # softirq_mask. unused delay slot + la t1, irq_stat # softirq_active +#ifdef CONFIG_SMP + lw t0, TASK_PROCESSOR($28) + sll t0, t0, 5 + addu t1, t0 +#endif + lw t0, 0(t1) # softirq_active + lw t1, 4(t1) # softirq_mask. unused delay slot and t0, t1 bnez t0, handle_softirq - 9: lw t0,PT_STATUS(sp) # returning to kernel mode? lw t2, TASK_NEED_RESCHED($28) andi t1, t0, KU_USER diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index e0986a61a4d0..0a961dd4799f 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c @@ -64,6 +64,61 @@ * Host: Reply: * $m0,10#2a +$00010203040506070809101112131415#42 * + * + * ============== + * MORE EXAMPLES: + * ============== + * + * For reference -- the following are the steps that one + * company took (RidgeRun Inc) to get remote gdb debugging + * going. In this scenario the host machine was a PC and the + * target platform was a Galileo EVB64120A MIPS evaluation + * board. + * + * Step 1: + * First download gdb-5.0.tar.gz from the internet. + * and then build/install the package. + * + * Example: + * $ tar zxf gdb-5.0.tar.gz + * $ cd gdb-5.0 + * $ ./configure --target=mips-linux-elf + * $ make + * $ install + * $ which mips-linux-elf-gdb + * /usr/local/bin/mips-linux-elf-gdb + * + * Step 2: + * Configure linux for remote debugging and build it. + * + * Example: + * $ cd ~/linux + * $ make menuconfig <go to "Kernel Hacking" and turn on remote debugging> + * $ make dep; make vmlinux + * + * Step 3: + * Download the kernel to the remote target and start + * the kernel running. It will promptly halt and wait + * for the host gdb session to connect. It does this + * since the "Kernel Hacking" option has defined + * CONFIG_REMOTE_DEBUG which in turn enables your calls + * to: + * set_debug_traps(); + * breakpoint(); + * + * Step 4: + * Start the gdb session on the host. + * + * Example: + * $ mips-linux-elf-gdb vmlinux + * (gdb) set remotebaud 115200 + * (gdb) target remote /dev/ttyS1 + * ...at this point you are connected to + * the remote target and can use gdb + * in the normal fasion. Setting + * breakpoints, single stepping, + * printing variables, etc. + * */ #include <linux/string.h> @@ -71,6 +126,8 @@ #include <linux/signal.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/console.h> +#include <linux/init.h> #include <asm/asm.h> #include <asm/mipsregs.h> @@ -315,13 +372,10 @@ static char *hex2mem(char *buf, char *mem, int count, int may_fault) * signals, which are primarily what GDB understands. It also indicates * which hardware traps we need to commandeer when initializing the stub. */ -static struct hard_trap_info -{ +static struct hard_trap_info { unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */ unsigned char signo; /* Signal that we map this trap into */ } hard_trap_info[] = { - { 4, SIGBUS }, /* address error (load) */ - { 5, SIGBUS }, /* address error (store) */ { 6, SIGBUS }, /* instruction bus error */ { 7, SIGBUS }, /* data bus error */ { 9, SIGTRAP }, /* break */ @@ -350,6 +404,7 @@ void set_debug_traps(void) for (ht = hard_trap_info; ht->tt && ht->signo; ht++) set_except_vector(ht->tt, trap_low); + putDebugChar('+'); /* 'hello world' */ /* * In case GDB is started before us, ack any packets * (presumably "$?#xx") sitting there. @@ -373,7 +428,7 @@ void set_debug_traps(void) */ extern void fltr_set_mem_err(void) { - /* FIXME: Needs to be written... */ + /* FIXME: Needs to be written... */ } /* @@ -401,8 +456,7 @@ static int hexToInt(char **ptr, int *intValue) *intValue = 0; - while (**ptr) - { + while (**ptr) { hexValue = hex(**ptr); if (hexValue < 0) break; @@ -904,3 +958,47 @@ void adel(void) lw $9,0($8) "); } + +#ifdef CONFIG_GDB_CONSOLE + +void gdb_puts(const char *str) +{ + int l = strlen(str); + char outbuf[18]; + + outbuf[0]='O'; + + while(l) { + int i = (l>8)?8:l; + mem2hex((char *)str, &outbuf[1], i, 0); + outbuf[(i*2)+1]=0; + putpacket(outbuf); + str += i; + l -= i; + } +} + +static kdev_t gdb_console_dev(struct console *con) +{ + return MKDEV(1, 3); /* /dev/null */ +} + +static void gdb_console_write(struct console *con, const char *s, unsigned n) +{ + gdb_puts(s); +} + +static struct console gdb_console = { + name: "gdb", + write: gdb_console_write, + device: gdb_console_dev, + flags: CON_PRINTBUFFER, + index: -1 +}; + +__init void register_gdb_console(void) +{ + register_console(&gdb_console); +} + +#endif diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index ea8610da3a32..1fd8c2590398 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -1,5 +1,4 @@ -/* $Id: head.S,v 1.18 2000/03/03 22:17:07 kevink Exp $ - * +/* * arch/mips/kernel/head.S * * This file is subject to the terms and conditions of the GNU General Public @@ -15,6 +14,14 @@ * Copyright (C) 1999 Silicon Graphics, Inc. * * Head.S contains the MIPS exception handler and startup code. + * + ************************************************************************** + * 9 Nov, 2000. + * Added Cache Error exception handler and SBDDP EJTAG debug exception. + * + * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + ************************************************************************** */ #include <linux/config.h> #include <linux/threads.h> @@ -52,9 +59,19 @@ .set noat LEAF(except_vec0_r4000) .set mips3 +#ifdef CONFIG_SMP + mfc0 k1, CP0_CONTEXT + la k0, current_pgd + srl k1, 23 + sll k1, 2 + addu k1, k0, k1 + lw k1, (k1) +#else + lw k1, current_pgd # get pgd pointer +#endif mfc0 k0, CP0_BADVADDR # Get faulting address srl k0, k0, 22 # get pgd only bits - lw k1, current_pgd # get pgd pointer + sll k0, k0, 2 addu k1, k1, k0 # add in pgd offset mfc0 k0, CP0_CONTEXT # get context reg @@ -69,8 +86,8 @@ srl k1, k1, 6 # convert to entrylo1 mtc0 k1, CP0_ENTRYLO1 # load it b 1f - tlbwr # write random tlb entry -1: + tlbwr # write random tlb entry +1: nop eret # return from trap END(except_vec0_r4000) @@ -308,12 +325,26 @@ /* Cache Error */ LEAF(except_vec2_generic) - /* Famous last words: unreached */ - mfc0 a1,CP0_ERROREPC - PRINT("Cache error exception: c0_errorepc == %08x\n") -1: - j 1b - nop + .set noat + .set mips0 + /* + * This is a very bad place to be. Our cache error + * detection has triggered. If we have write-back data + * in the cache, we may not be able to recover. As a + * first-order desperate measure, turn off KSEG0 cacheing. + */ + mfc0 k0,CP0_CONFIG + li k1,~CONF_CM_CMASK + and k0,k0,k1 + ori k0,k0,CONF_CM_UNCACHED + mtc0 k0,CP0_CONFIG + /* Give it a few cycles to sink in... */ + nop + nop + nop + + j cache_parity_error + nop END(except_vec2_generic) /* General exception vector R4000 version. */ @@ -338,6 +369,7 @@ * c0_badvaddr because after return from this exception handler the load / * store will be re-executed. */ + .set mips3 handle_vced: mfc0 k0, CP0_BADVADDR li k1, -4 @@ -393,6 +425,38 @@ handle_vcei: nop END(except_vec4) + /* + * SBDDP EJTAG debug exception handler. + * The EJTAG debug exception entry point is 0xbfc00480, which + * normally is in the boot PROM, so the boot PROM must do a + * unconditional jump to this vector. + */ + NESTED(except_vec_ejtag_debug, 0, sp) + j ejtag_debug_handler + nop + END(except_vec_ejtag_debug) + + /* + * EJTAG debug exception handler. + */ + NESTED(ejtag_debug_handler, PT_SIZE, sp) + .set noat + .set noreorder + SAVE_ALL + PRINT("SDBBP EJTAG debug exception - not handled yet, just ignored!\n"); + mfc0 k0, $23 # Get EJTAG Debug register. + mfc0 k1, $24 # Get DEPC register. + bgez k0, 1f + addiu k1, k1, 4 # SBDDP inst. in delay slot. + addiu k1, k1, 4 +1: mtc0 k1, $24 + RESTORE_ALL + .word 0x4200001f # deret, return EJTAG debug exception. + nop + .set at + END(ejtag_debug_handler) + + /* * Kernel entry point */ @@ -407,9 +471,9 @@ NESTED(kernel_entry, 16, sp) */ la $28, init_task_union addiu t0, $28, KERNEL_STACK_SIZE-32 - sw t0, kernelsp subu sp, t0, 4*SZREG + sw t0, kernelsp /* The firmware/bootloader passes argc/argp/envp * to us as arguments. But clear bss first because * the romvec and other important info is stored there @@ -427,6 +491,30 @@ NESTED(kernel_entry, 16, sp) nop END(kernel_entry) + +#ifdef CONFIG_SMP + +/* + * SMP slave cpus entry point. Board specific code + * for bootstrap calls this function after setting up + * the stack and gp registers. + */ + LEAF(smp_bootstrap) + .set push + .set noreorder + mtc0 zero, CP0_WIRED + CLI + mfc0 t0, CP0_STATUS + li t1, ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_BEV); + and t0, t1 + or t0, (ST0_CU0|ST0_KX|ST0_SX|ST0_FR); + addiu a0, zero, 0 + jal start_secondary + mtc0 t0, CP0_STATUS + .set pop + END(smp_bootstrap) +#endif + /* * This buffer is reserved for the use of the cache error handler. */ @@ -434,12 +522,19 @@ NESTED(kernel_entry, 16, sp) EXPORT(cache_error_buffer) .fill 32*4,1,0 +#ifndef CONFIG_SMP EXPORT(kernelsp) PTR 0 EXPORT(current_pgd) - PTR 0 + PTR 0 +#else + /* There's almost certainly a better way to do this with the macros...*/ + .globl kernelsp + .comm kernelsp, NR_CPUS * 8, 8 + .globl current_pgd + .comm current_pgd, NR_CPUS * 8, 8 +#endif .text - .org 0x1000 EXPORT(swapper_pg_dir) diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c new file mode 100644 index 000000000000..ca7b100b360d --- /dev/null +++ b/arch/mips/kernel/i8259.c @@ -0,0 +1,308 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Code to handle x86 style IRQs plus some generic interrupt stuff. + * + * Copyright (C) 1992 Linus Torvalds + * Copyright (C) 1994 - 2000 Ralf Baechle + */ +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> + +#include <asm/io.h> + +void enable_8259A_irq(unsigned int irq); +void disable_8259A_irq(unsigned int irq); + +/* + * This is the 'legacy' 8259A Programmable Interrupt Controller, + * present in the majority of PC/AT boxes. + * plus some generic x86 specific things if generic specifics makes + * any sense at all. + * this file should become arch/i386/kernel/irq.c when the old irq.c + * moves to arch independent land + */ + +spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; + +static void end_8259A_irq (unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_8259A_irq(irq); +} + +#define shutdown_8259A_irq disable_8259A_irq + +void mask_and_ack_8259A(unsigned int); + +static unsigned int startup_8259A_irq(unsigned int irq) +{ + enable_8259A_irq(irq); + + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type i8259A_irq_type = { + "XT-PIC", + startup_8259A_irq, + shutdown_8259A_irq, + enable_8259A_irq, + disable_8259A_irq, + mask_and_ack_8259A, + end_8259A_irq, + NULL +}; + +/* + * 8259A PIC functions to handle ISA devices: + */ + +/* + * This contains the irq mask for both 8259A irq controllers, + */ +static unsigned int cached_irq_mask = 0xffff; + +#define __byte(x,y) (((unsigned char *)&(y))[x]) +#define cached_21 (__byte(0,cached_irq_mask)) +#define cached_A1 (__byte(1,cached_irq_mask)) + +void disable_8259A_irq(unsigned int irq) +{ + unsigned int mask = 1 << irq; + unsigned long flags; + + spin_lock_irqsave(&i8259A_lock, flags); + cached_irq_mask |= mask; + if (irq & 8) + outb(cached_A1,0xA1); + else + outb(cached_21,0x21); + spin_unlock_irqrestore(&i8259A_lock, flags); +} + +void enable_8259A_irq(unsigned int irq) +{ + unsigned int mask = ~(1 << irq); + unsigned long flags; + + spin_lock_irqsave(&i8259A_lock, flags); + cached_irq_mask &= mask; + if (irq & 8) + outb(cached_A1,0xA1); + else + outb(cached_21,0x21); + spin_unlock_irqrestore(&i8259A_lock, flags); +} + +int i8259A_irq_pending(unsigned int irq) +{ + unsigned int mask = 1 << irq; + unsigned long flags; + int ret; + + spin_lock_irqsave(&i8259A_lock, flags); + if (irq < 8) + ret = inb(0x20) & mask; + else + ret = inb(0xA0) & (mask >> 8); + spin_unlock_irqrestore(&i8259A_lock, flags); + + return ret; +} + +void make_8259A_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + irq_desc[irq].handler = &i8259A_irq_type; + enable_irq(irq); +} + +/* + * This function assumes to be called rarely. Switching between + * 8259A registers is slow. + * This has to be protected by the irq controller spinlock + * before being called. + */ +static inline int i8259A_irq_real(unsigned int irq) +{ + int value; + int irqmask = 1 << irq; + + if (irq < 8) { + outb(0x0B,0x20); /* ISR register */ + value = inb(0x20) & irqmask; + outb(0x0A,0x20); /* back to the IRR register */ + return value; + } + outb(0x0B,0xA0); /* ISR register */ + value = inb(0xA0) & (irqmask >> 8); + outb(0x0A,0xA0); /* back to the IRR register */ + return value; +} + +/* + * Careful! The 8259A is a fragile beast, it pretty + * much _has_ to be done exactly like this (mask it + * first, _then_ send the EOI, and the order of EOI + * to the two 8259s is important! + */ +void mask_and_ack_8259A(unsigned int irq) +{ + unsigned int irqmask = 1 << irq; + unsigned long flags; + + spin_lock_irqsave(&i8259A_lock, flags); + /* + * Lightweight spurious IRQ detection. We do not want to overdo + * spurious IRQ handling - it's usually a sign of hardware problems, so + * we only do the checks we can do without slowing down good hardware + * nnecesserily. + * + * Note that IRQ7 and IRQ15 (the two spurious IRQs usually resulting + * rom the 8259A-1|2 PICs) occur even if the IRQ is masked in the 8259A. + * Thus we can check spurious 8259A IRQs without doing the quite slow + * i8259A_irq_real() call for every IRQ. This does not cover 100% of + * spurious interrupts, but should be enough to warn the user that + * there is something bad going on ... + */ + if (cached_irq_mask & irqmask) + goto spurious_8259A_irq; + cached_irq_mask |= irqmask; + +handle_real_irq: + if (irq & 8) { + inb(0xA1); /* DUMMY - (do we need this?) */ + outb(cached_A1,0xA1); + outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */ + outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */ + } else { + inb(0x21); /* DUMMY - (do we need this?) */ + outb(cached_21,0x21); + outb(0x60+irq,0x20); /* 'Specific EOI' to master */ + } + spin_unlock_irqrestore(&i8259A_lock, flags); + return; + +spurious_8259A_irq: + /* + * this is the slow path - should happen rarely. + */ + if (i8259A_irq_real(irq)) + /* + * oops, the IRQ _is_ in service according to the + * 8259A - not spurious, go handle it. + */ + goto handle_real_irq; + + { + static int spurious_irq_mask = 0; + /* + * At this point we can be sure the IRQ is spurious, + * lets ACK and report it. [once per IRQ] + */ + if (!(spurious_irq_mask & irqmask)) { + printk("spurious 8259A interrupt: IRQ%d.\n", irq); + spurious_irq_mask |= irqmask; + } + irq_err_count++; + /* + * Theoretically we do not have to handle this IRQ, + * but in Linux this does not cause problems and is + * simpler for us. + */ + goto handle_real_irq; + } +} + +void __init init_8259A(int auto_eoi) +{ + unsigned long flags; + + spin_lock_irqsave(&i8259A_lock, flags); + + outb(0xff, 0x21); /* mask all of 8259A-1 */ + outb(0xff, 0xA1); /* mask all of 8259A-2 */ + + /* + * outb_p - this has to work on a wide range of PC hardware. + */ + outb_p(0x11, 0x20); /* ICW1: select 8259A-1 init */ + outb_p(0x20 + 0, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */ + outb_p(0x04, 0x21); /* 8259A-1 (the master) has a slave on IR2 */ + if (auto_eoi) + outb_p(0x03, 0x21); /* master does Auto EOI */ + else + outb_p(0x01, 0x21); /* master expects normal EOI */ + + outb_p(0x11, 0xA0); /* ICW1: select 8259A-2 init */ + outb_p(0x20 + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */ + outb_p(0x02, 0xA1); /* 8259A-2 is a slave on master's IR2 */ + outb_p(0x01, 0xA1); /* (slave's support for AEOI in flat mode + is to be investigated) */ + + if (auto_eoi) + /* + * in AEOI mode we just have to mask the interrupt + * when acking. + */ + i8259A_irq_type.ack = disable_8259A_irq; + else + i8259A_irq_type.ack = mask_and_ack_8259A; + + udelay(100); /* wait for 8259A to initialize */ + + outb(cached_21, 0x21); /* restore master IRQ mask */ + outb(cached_A1, 0xA1); /* restore slave IRQ mask */ + + spin_unlock_irqrestore(&i8259A_lock, flags); +} + +asmlinkage void i8259_do_irq(int irq, struct pt_regs regs) +{ + panic("i8259_do_irq: I want to be implemented"); +} + +/* + * IRQ2 is cascade interrupt to second interrupt controller + */ +static struct irqaction irq2 = { + no_action, 0, 0, "cascade", NULL, NULL +}; + +static struct resource pic1_io_resource = { + "pic1", 0x20, 0x3f, IORESOURCE_BUSY +}; + +static struct resource pic2_io_resource = { + "pic2", 0xa0, 0xbf, IORESOURCE_BUSY +}; + +/* + * On systems with i8259-style interrupt controllers we assume for + * driver compatibility reasons interrupts 0 - 15 to be the i8295 + * interrupts even if the hardware uses a different interrupt numbering. + */ +void __init init_i8259_irqs (void) +{ + int i; + + request_resource(&ioport_resource, &pic1_io_resource); + request_resource(&ioport_resource, &pic2_io_resource); + setup_irq(2, &irq2); + + init_8259A(0); + + for (i = 0; i < 16; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + irq_desc[i].handler = &i8259A_irq_type; + } +} diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index 66c37fefc81e..900e1004f82b 100644 --- a/arch/mips/kernel/irixsig.c +++ b/arch/mips/kernel/irixsig.c @@ -714,7 +714,7 @@ repeat: SET_LINKS(p); notify_parent(p, SIGCHLD); } else - release(p); + release_task(p); goto end_waitsys; default: continue; diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index f6b1cecce95f..39956dc0c8f9 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -8,289 +8,367 @@ * Copyright (C) 1992 Linus Torvalds * Copyright (C) 1994 - 2000 Ralf Baechle */ -#include <linux/config.h> -#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/irq.h> #include <linux/init.h> -#include <linux/kernel_stat.h> -#include <linux/module.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/types.h> #include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/timex.h> +#include <linux/kernel_stat.h> #include <linux/slab.h> +#include <linux/mm.h> #include <linux/random.h> +#include <linux/sched.h> -#include <asm/bitops.h> -#include <asm/bootinfo.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/mipsregs.h> #include <asm/system.h> -#include <asm/sni.h> -#include <asm/nile4.h> /* - * Linux has a controller-independent x86 interrupt architecture. - * every controller has a 'controller-template', that is used - * by the main code to do the right thing. Each driver-visible - * interrupt source is transparently wired to the apropriate - * controller. Thus drivers need not be aware of the - * interrupt-controller. - * - * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, - * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. - * (IO-APICs assumed to be messaging to Pentium local-APICs) - * - * the code is designed to be easily extended with new/different - * interrupt controllers, without having to do assembly magic. + * Controller mappings for all interrupt sources: */ +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = + { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; /* - * This contains the irq mask for both 8259A irq controllers, it's an - * int so we can deal with the third PIC in some systems like the RM300. - * (XXX This is broken for big endian.) + * Special irq handlers. */ -static unsigned int cached_irq_mask = 0xffff; -#define __byte(x,y) (((unsigned char *)&(y))[x]) -#define __word(x,y) (((unsigned short *)&(y))[x]) -#define __long(x,y) (((unsigned int *)&(y))[x]) - -#define cached_21 (__byte(0,cached_irq_mask)) -#define cached_A1 (__byte(1,cached_irq_mask)) - -unsigned long spurious_count = 0; +void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } /* - * (un)mask_irq, disable_irq() and enable_irq() only handle (E)ISA and - * PCI devices. Other onboard hardware needs specific routines. + * Generic no controller code */ -static inline void mask_irq(unsigned int irq) -{ - cached_irq_mask |= 1 << irq; - if (irq & 8) { - outb(cached_A1, 0xa1); - } else { - outb(cached_21, 0x21); - } -} -static inline void unmask_irq(unsigned int irq) +static void enable_none(unsigned int irq) { } +static unsigned int startup_none(unsigned int irq) { return 0; } +static void disable_none(unsigned int irq) { } +static void ack_none(unsigned int irq) { - cached_irq_mask &= ~(1 << irq); - if (irq & 8) { - outb(cached_A1, 0xa1); - } else { - outb(cached_21, 0x21); - } + /* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves, it doesnt deserve + * a generic callback i think. + */ + printk("unexpected interrupt %d\n", irq); } -void i8259_disable_irq(unsigned int irq_nr) -{ - unsigned long flags; +/* startup is the same as "enable", shutdown is same as "disable" */ +#define shutdown_none disable_none +#define end_none enable_none + +struct hw_interrupt_type no_irq_type = { + "none", + startup_none, + shutdown_none, + enable_none, + disable_none, + ack_none, + end_none +}; - save_and_cli(flags); - mask_irq(irq_nr); - restore_flags(flags); -} +volatile unsigned long irq_err_count, spurious_count; -void i8259_enable_irq(unsigned int irq_nr) -{ - unsigned long flags; - save_and_cli(flags); - unmask_irq(irq_nr); - restore_flags(flags); -} - -static struct irqaction *irq_action[NR_IRQS] = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; +/* + * Generic, controller-independent functions: + */ int get_irq_list(char *buf) { - int i, len = 0; struct irqaction * action; + char *p = buf; + int i; - for (i = 0 ; i < 32 ; i++) { - action = irq_action[i]; + p += sprintf(p, " "); + for (i=0; i < 1 /*smp_num_cpus*/; i++) + p += sprintf(p, "CPU%d ", i); + *p++ = '\n'; + + for (i = 0 ; i < NR_IRQS ; i++) { + action = irq_desc[i].action; if (!action) continue; - len += sprintf(buf+len, "%2d: %8d %c %s", - i, kstat.irqs[0][i], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); - } - len += sprintf(buf+len, "\n"); + p += sprintf(p, "%3d: ",i); + p += sprintf(p, "%10u ", kstat_irqs(i)); + p += sprintf(p, " %14s", irq_desc[i].handler->typename); + p += sprintf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) + p += sprintf(p, ", %s", action->name); + *p++ = '\n'; } - return len; -} - -static inline void i8259_mask_and_ack_irq(int irq) -{ - cached_irq_mask |= 1 << irq; - - if (irq & 8) { - inb(0xa1); - outb(cached_A1, 0xa1); - outb(0x62, 0x20); /* Specific EOI to cascade */ - outb(0x20, 0xa0); - } else { - inb(0x21); - outb(cached_21, 0x21); - outb(0x20, 0x20); - } + p += sprintf(p, "ERR: %10lu\n", irq_err_count); + return p - buf; } -asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs) +/* + * This should really return information about whether + * we should do bottom half handling etc. Right now we + * end up _always_ checking the bottom half, which is a + * waste of time and is not what some drivers would + * prefer. + */ +int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { - struct irqaction *action; - int do_random, cpu; - - cpu = smp_processor_id(); - irq_enter(cpu); - - if (irq >= 16) - goto out; - - i8259_mask_and_ack_irq(irq); + int status; + int cpu = smp_processor_id(); - kstat.irqs[cpu][irq]++; + irq_enter(cpu, irq); - action = *(irq + irq_action); - if (!action) - goto out; + status = 1; /* Force the "do bottom halves" bit */ if (!(action->flags & SA_INTERRUPT)) __sti(); - action = *(irq + irq_action); - do_random = 0; - do { - do_random |= action->flags; + + do { + status |= action->flags; action->handler(irq, action->dev_id, regs); action = action->next; - } while (action); - if (do_random & SA_SAMPLE_RANDOM) + } while (action); + if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); __cli(); - unmask_irq (irq); -out: - irq_exit(cpu); + irq_exit(cpu, irq); + + return status; } /* - * do_IRQ handles IRQ's that have been installed without the - * SA_INTERRUPT flag: it uses the full signal-handling return - * and runs with other interrupts enabled. All relatively slow - * IRQ's should use this format: notably the keyboard/timer - * routines. + * Generic enable/disable code: this just calls + * down into the PIC-specific version for the actual + * hardware disable after having gotten the irq + * controller lock. */ -asmlinkage void do_IRQ(int irq, struct pt_regs * regs) + +/** + * disable_irq_nosync - disable an irq without waiting + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables of an interrupt + * stack. Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. + * + * This function may be called from IRQ context. + */ + +void inline disable_irq_nosync(unsigned int irq) { - struct irqaction *action; - int do_random, cpu; - - cpu = smp_processor_id(); - irq_enter(cpu); - kstat.irqs[cpu][irq]++; + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; - action = *(irq + irq_action); - if (action) { - if (!(action->flags & SA_INTERRUPT)) - __sti(); - action = *(irq + irq_action); - do_random = 0; - do { - do_random |= action->flags; - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - if (do_random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - __cli(); + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); } - irq_exit(cpu); + spin_unlock_irqrestore(&desc->lock, flags); +} - if (softirq_active(cpu)&softirq_mask(cpu)) - do_softirq(); +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables of an interrupt + * stack. That is for two disables you need two enables. This + * function waits for any pending IRQ handlers for this interrupt + * to complete before returning. If you use this function while + * holding a resource the IRQ handler may need you will deadlock. + * + * This function may be called - with care - from IRQ context. + */ + +void disable_irq(unsigned int irq) +{ + disable_irq_nosync(irq); - /* unmasking and bottom half handling is done magically for us. */ + if (!local_irq_count(smp_processor_id())) { + do { + barrier(); + } while (irq_desc[irq].status & IRQ_INPROGRESS); + } } -int i8259_setup_irq(int irq, struct irqaction * new) +/** + * enable_irq - enable interrupt handling on an irq + * @irq: Interrupt to enable + * + * Re-enables the processing of interrupts on this IRQ line + * providing no disable_irq calls are now in effect. + * + * This function may be called from IRQ context. + */ + +void enable_irq(unsigned int irq) { - int shared = 0; - struct irqaction *old, **p; + irq_desc_t *desc = irq_desc + irq; unsigned long flags; - p = irq_action + irq; - if ((old = *p) != NULL) { - /* Can't share interrupts unless both agree to */ - if (!(old->flags & new->flags & SA_SHIRQ)) - return -EBUSY; - - /* Can't share interrupts unless both are same type */ - if ((old->flags ^ new->flags) & SA_INTERRUPT) - return -EBUSY; - - /* add new interrupt at end of irq queue */ - do { - p = &old->next; - old = *p; - } while (old); - shared = 1; + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { + case 1: { + unsigned int status = desc->status & ~IRQ_DISABLED; + desc->status = status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); + } + desc->handler->enable(irq); + /* fall-through */ + } + default: + desc->depth--; + break; + case 0: + printk("enable_irq(%u) unbalanced from %p\n", irq, + __builtin_return_address(0)); } + spin_unlock_irqrestore(&desc->lock, flags); +} - if (new->flags & SA_SAMPLE_RANDOM) - rand_initialize_irq(irq); +/* + * do_IRQ handles all normal device IRQ's (the special + * SMP cross-CPU interrupts have their own specific + * handlers). + */ +asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs) +{ + /* + * We ack quickly, we don't want the irq controller + * thinking we're snobs just because some other CPU has + * disabled global interrupts (we have already done the + * INT_ACK cycles, it's too late to try to pretend to the + * controller that we aren't taking the interrupt). + * + * 0 return value means that this irq is already being + * handled by some other CPU. (or is disabled) + */ + int cpu = smp_processor_id(); + irq_desc_t *desc = irq_desc + irq; + struct irqaction * action; + unsigned int status; - save_and_cli(flags); - *p = new; + kstat.irqs[cpu][irq]++; + spin_lock(&desc->lock); + desc->handler->ack(irq); + /* + REPLAY is when Linux resends an IRQ that was dropped earlier + WAITING is used by probe to mark irqs that are being tested + */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + status |= IRQ_PENDING; /* we _want_ to handle it */ + + /* + * If the IRQ is disabled for whatever reason, we cannot + * use the action we have. + */ + action = NULL; + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + action = desc->action; + status &= ~IRQ_PENDING; /* we commit to handling */ + status |= IRQ_INPROGRESS; /* we are handling it */ + } + desc->status = status; + + /* + * If there is no IRQ handler or it was disabled, exit early. + Since we set PENDING, if another processor is handling + a different instance of this same irq, the other processor + will take care of it. + */ + if (!action) + goto out; - if (!shared) { - if (is_i8259_irq(irq)) - unmask_irq(irq); -#if CONFIG_DDB5074 /* This has no business here */ - else - nile4_enable_irq(irq_to_nile4(irq)); -#endif + /* + * Edge triggered interrupts need to remember + * pending events. + * This applies to any hw interrupts that allow a second + * instance of the same irq to arrive while we are in do_IRQ + * or in the handler. But the code here only handles the _second_ + * instance of the irq, not the third or fourth. So it is mostly + * useful for irq hardware that does not mask cleanly in an + * SMP environment. + */ + for (;;) { + spin_unlock(&desc->lock); + handle_IRQ_event(irq, regs, action); + spin_lock(&desc->lock); + + if (!(desc->status & IRQ_PENDING)) + break; + desc->status &= ~IRQ_PENDING; } - restore_flags(flags); - return 0; + desc->status &= ~IRQ_INPROGRESS; +out: + /* + * The ->end() handler has to deal with interrupts which got + * disabled while the handler was running. + */ + desc->handler->end(irq); + spin_unlock(&desc->lock); + + if (softirq_active(cpu) & softirq_mask(cpu)) + do_softirq(); + return 1; } -/* - * Request_interrupt and free_interrupt ``sort of'' handle interrupts of - * non i8259 devices. They will have to be replaced by architecture - * specific variants. For now we still use this as broken as it is because - * it used to work ... +/** + * request_irq - allocate an interrupt line + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt line and IRQ handling. From the point this + * call is made your handler function may be invoked. Since + * your handler function must clear any interrupt the board + * raises, you must take care both to initialise your hardware + * and to set up the interrupt handler in the right order. + * + * Dev_id must be globally unique. Normally the address of the + * device data structure is used as the cookie. Since the handler + * receives this value it makes sense to use it. + * + * If your interrupt is shared you must pass a non NULL dev_id + * as this is required when freeing the interrupt. + * + * Flags: + * + * SA_SHIRQ Interrupt is shared + * + * SA_INTERRUPT Disable local interrupts while processing + * + * SA_SAMPLE_RANDOM The interrupt can be used for entropy + * */ + int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char * devname, void *dev_id) + unsigned long irqflags, + const char * devname, + void *dev_id) { int retval; struct irqaction * action; - if (irq >= 32) +#if 1 + /* + * Sanity-check: shared interrupts should REALLY pass in + * a real dev-ID, otherwise we'll have trouble later trying + * to figure out which interrupt is which (messes up the + * interrupt freeing logic etc). + */ + if (irqflags & SA_SHIRQ) { + if (!dev_id) + printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]); + } +#endif + + if (irq >= NR_IRQS) return -EINVAL; if (!handler) return -EINVAL; - action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_KERNEL); if (!action) return -ENOMEM; @@ -301,107 +379,329 @@ int request_irq(unsigned int irq, action->next = NULL; action->dev_id = dev_id; - retval = i8259_setup_irq(irq, action); - + retval = setup_irq(irq, action); if (retval) kfree(action); return retval; } - + +/** + * free_irq - free an interrupt + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Remove an interrupt handler. The handler is removed and if the + * interrupt line is no longer in use by any driver it is disabled. + * On a shared IRQ the caller must ensure the interrupt is disabled + * on the card it drives before calling this function. The function + * does not return until any executing interrupts for this IRQ + * have completed. + * + * This function may be called from interrupt context. + * + * Bugs: Attempting to free an irq in a handler for the same irq hangs + * the machine. + */ + void free_irq(unsigned int irq, void *dev_id) { - struct irqaction * action, **p; + irq_desc_t *desc; + struct irqaction **p; unsigned long flags; - if (irq > 31) { - printk("Trying to free IRQ%d\n",irq); + if (irq >= NR_IRQS) return; - } - for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { - if (action->dev_id != dev_id) - continue; - /* Found it - now free it */ - save_and_cli(flags); - *p = action->next; - if (!irq[irq_action]) - mask_irq(irq); - restore_flags(flags); - kfree(action); + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + for (;;) { + struct irqaction * action = *p; + if (action) { + struct irqaction **pp = p; + p = &action->next; + if (action->dev_id != dev_id) + continue; + + /* Found it - now remove it from the list of entries */ + *pp = action->next; + if (!desc->action) { + desc->status |= IRQ_DISABLED; + desc->handler->shutdown(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + +#ifdef CONFIG_SMP + /* Wait to make sure it's not being used on another CPU */ + while (desc->status & IRQ_INPROGRESS) + barrier(); +#endif + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n",irq); + spin_unlock_irqrestore(&desc->lock,flags); return; } - printk("Trying to free free IRQ%d\n",irq); } -unsigned long probe_irq_on (void) +/* + * IRQ autodetection code.. + * + * This depends on the fact that any interrupt that + * comes in on to an unassigned handler will get stuck + * with "IRQ_WAITING" cleared and the interrupt + * disabled. + */ + +static DECLARE_MUTEX(probe_sem); + +/** + * probe_irq_on - begin an interrupt autodetect + * + * Commence probing for an interrupt. The interrupts are scanned + * and a mask of potential interrupt lines is returned. + * + */ + +unsigned long probe_irq_on(void) { - unsigned int i, irqs = 0; + unsigned int i; + irq_desc_t *desc; + unsigned long val; unsigned long delay; - /* first, enable any unassigned (E)ISA irqs */ - for (i = 15; i > 0; i--) { - if (!irq_action[i]) { - i8259_enable_irq(i); - irqs |= (1 << i); + down(&probe_sem); + /* + * something may have generated an irq long ago and we want to + * flush such a longstanding irq before considering it as spurious. + */ + for (i = NR_IRQS-1; i > 0; i--) { + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!irq_desc[i].action) + irq_desc[i].handler->startup(i); + spin_unlock_irq(&desc->lock); + } + + /* Wait for longstanding interrupts to trigger. */ + for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) + /* about 20ms delay */ synchronize_irq(); + + /* + * enable any unassigned irqs + * (we must startup again here because if a longstanding irq + * happened in the previous stage, it may have masked itself) + */ + for (i = NR_IRQS-1; i > 0; i--) { + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!desc->action) { + desc->status |= IRQ_AUTODETECT | IRQ_WAITING; + if (desc->handler->startup(i)) + desc->status |= IRQ_PENDING; } + spin_unlock_irq(&desc->lock); } - /* wait for spurious interrupts to mask themselves out again */ - for (delay = jiffies + HZ/10; time_before(jiffies, delay); ) - /* about 100ms delay */; + /* + * Wait for spurious interrupts to trigger + */ + for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) + /* about 100ms delay */ synchronize_irq(); + + /* + * Now filter out any obviously spurious interrupts + */ + val = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + /* It triggered already - consider it spurious. */ + if (!(status & IRQ_WAITING)) { + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } else + if (i < 32) + val |= 1 << i; + } + spin_unlock_irq(&desc->lock); + } - /* now filter out any obviously spurious interrupts */ - return irqs & ~cached_irq_mask; + return val; } -int probe_irq_off (unsigned long irqs) +/* + * Return a mask of triggered interrupts (this + * can handle only legacy ISA interrupts). + */ + +/** + * probe_irq_mask - scan a bitmap of interrupt lines + * @val: mask of interrupts to consider + * + * Scan the ISA bus interrupt lines and return a bitmap of + * active interrupts. The interrupt probe logic state is then + * returned to its previous value. + * + * Note: we need to scan all the irq's even though we will + * only return ISA irq numbers - just so that we reset them + * all to a known state. + */ +unsigned int probe_irq_mask(unsigned long val) { - unsigned int i; + int i; + unsigned int mask; -#ifdef DEBUG - printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask); -#endif - irqs &= cached_irq_mask; - if (!irqs) - return 0; - i = ffz(~irqs); - if (irqs != (irqs & (1 << i))) - i = -i; - return i; + mask = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + if (i < 16 && !(status & IRQ_WAITING)) + mask |= 1 << i; + + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); + } + up(&probe_sem); + + return mask & val; } -int (*irq_cannonicalize)(int irq); +/* + * Return the one interrupt that triggered (this can + * handle any interrupt source). + */ -static int i8259_irq_cannonicalize(int irq) +/** + * probe_irq_off - end an interrupt autodetect + * @val: mask of potential interrupts (unused) + * + * Scans the unused interrupt lines and returns the line which + * appears to have triggered the interrupt. If no interrupt was + * found then zero is returned. If more than one interrupt is + * found then minus the first candidate is returned to indicate + * their is doubt. + * + * The interrupt probe logic state is returned to its previous + * value. + * + * BUGS: When used in a module (which arguably shouldnt happen) + * nothing prevents two IRQ probe callers from overlapping. The + * results of this are non-optimal. + */ + +int probe_irq_off(unsigned long val) { - return ((irq == 2) ? 9 : irq); + int i, irq_found, nr_irqs; + + nr_irqs = 0; + irq_found = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + if (!(status & IRQ_WAITING)) { + if (!nr_irqs) + irq_found = i; + nr_irqs++; + } + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); + } + up(&probe_sem); + + if (nr_irqs > 1) + irq_found = -irq_found; + return irq_found; } -void __init i8259_init(void) +/* this was setup_x86_irq but it seems pretty generic */ +int setup_irq(unsigned int irq, struct irqaction * new) { - /* Init master interrupt controller */ - outb(0x11, 0x20); /* Start init sequence */ - outb(0x00, 0x21); /* Vector base */ - outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */ - outb(0x01, 0x21); /* Select 8086 mode */ - outb(0xff, 0x21); /* Mask all */ - - /* Init slave interrupt controller */ - outb(0x11, 0xa0); /* Start init sequence */ - outb(0x08, 0xa1); /* Vector base */ - outb(0x02, 0xa1); /* edge triggered, Cascade (slave) on IRQ2 */ - outb(0x01, 0xa1); /* Select 8086 mode */ - outb(0xff, 0xa1); /* Mask all */ - - outb(cached_A1, 0xa1); - outb(cached_21, 0x21); + int shared = 0; + unsigned long flags; + struct irqaction *old, **p; + irq_desc_t *desc = irq_desc + irq; + + /* + * Some drivers like serial.c use request_irq() heavily, + * so we have to be careful not to interfere with a + * running system. + */ + if (new->flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(irq); + } + + /* + * The following block of code has to be executed atomically + */ + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { + spin_unlock_irqrestore(&desc->lock,flags); + return -EBUSY; + } + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + *p = new; + + if (!shared) { + desc->depth = 0; + desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING); + desc->handler->startup(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + + /* register_irq_proc(irq); */ + return 0; } -void __init init_IRQ(void) +void __init init_generic_irq(void) { - irq_cannonicalize = i8259_irq_cannonicalize; - /* i8259_init(); */ - irq_setup(); -} + int i; -EXPORT_SYMBOL(irq_cannonicalize); + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &no_irq_type; + } +} diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index 73d962476abc..476419edf9d1 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -5,7 +5,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996, 1997, 1998, 2000 by Ralf Baechle + * Copyright (C) 1996, 1997, 1998, 2000, 2001 by Ralf Baechle */ #include <linux/config.h> #include <linux/module.h> @@ -94,9 +94,10 @@ EXPORT_SYMBOL(invalid_pte_table); /* * Semaphore stuff */ -EXPORT_SYMBOL(__down_read); -EXPORT_SYMBOL(__down_write); -EXPORT_SYMBOL(__rwsem_wake); +EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_interruptible); +EXPORT_SYMBOL(__down_trylock); +EXPORT_SYMBOL(__up); /* * Base address of ports for Intel style I/O. diff --git a/arch/mips/kernel/old-irq.c b/arch/mips/kernel/old-irq.c new file mode 100644 index 000000000000..a5dfa2542916 --- /dev/null +++ b/arch/mips/kernel/old-irq.c @@ -0,0 +1,405 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Code to handle x86 style IRQs plus some generic interrupt stuff. + * + * Copyright (C) 1992 Linus Torvalds + * Copyright (C) 1994 - 2001 Ralf Baechle + * + * Old rotten IRQ code. To be killed as soon as everybody had converted or + * in 2.5.0, whatever comes first. + */ +#include <linux/config.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/module.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/timex.h> +#include <linux/slab.h> +#include <linux/random.h> + +#include <asm/bitops.h> +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/mipsregs.h> +#include <asm/system.h> +#include <asm/nile4.h> + +/* + * The board specific setup routine sets irq_setup to point to a board + * specific setup routine. + */ +void (*irq_setup)(void); + +/* + * Linux has a controller-independent x86 interrupt architecture. + * every controller has a 'controller-template', that is used + * by the main code to do the right thing. Each driver-visible + * interrupt source is transparently wired to the apropriate + * controller. Thus drivers need not be aware of the + * interrupt-controller. + * + * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, + * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. + * (IO-APICs assumed to be messaging to Pentium local-APICs) + * + * the code is designed to be easily extended with new/different + * interrupt controllers, without having to do assembly magic. + */ + +/* + * This contains the irq mask for both 8259A irq controllers, it's an + * int so we can deal with the third PIC in some systems like the RM300. + * (XXX This is broken for big endian.) + */ +static unsigned int cached_irq_mask = 0xffff; + +#define __byte(x,y) (((unsigned char *)&(y))[x]) +#define __word(x,y) (((unsigned short *)&(y))[x]) +#define __long(x,y) (((unsigned int *)&(y))[x]) + +#define cached_21 (__byte(0,cached_irq_mask)) +#define cached_A1 (__byte(1,cached_irq_mask)) + +unsigned long spurious_count = 0; + +/* + * (un)mask_irq, disable_irq() and enable_irq() only handle (E)ISA and + * PCI devices. Other onboard hardware needs specific routines. + */ +static inline void mask_irq(unsigned int irq) +{ + cached_irq_mask |= 1 << irq; + if (irq & 8) { + outb(cached_A1, 0xa1); + } else { + outb(cached_21, 0x21); + } +} + +static inline void unmask_irq(unsigned int irq) +{ + cached_irq_mask &= ~(1 << irq); + if (irq & 8) { + outb(cached_A1, 0xa1); + } else { + outb(cached_21, 0x21); + } +} + +void i8259_disable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + save_and_cli(flags); + mask_irq(irq_nr); + restore_flags(flags); +} + +void i8259_enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + save_and_cli(flags); + unmask_irq(irq_nr); + restore_flags(flags); +} + +static struct irqaction *irq_action[NR_IRQS] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +int get_irq_list(char *buf) +{ + int i, len = 0; + struct irqaction * action; + + for (i = 0 ; i < 32 ; i++) { + action = irq_action[i]; + if (!action) + continue; + len += sprintf(buf+len, "%2d: %8d %c %s", + i, kstat.irqs[0][i], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ",%s %s", + (action->flags & SA_INTERRUPT) ? " +" : "", + action->name); + } + len += sprintf(buf+len, "\n"); + } + return len; +} + +static inline void i8259_mask_and_ack_irq(int irq) +{ + cached_irq_mask |= 1 << irq; + + if (irq & 8) { + inb(0xa1); + outb(cached_A1, 0xa1); + outb(0x62, 0x20); /* Specific EOI to cascade */ + outb(0x20, 0xa0); + } else { + inb(0x21); + outb(cached_21, 0x21); + outb(0x20, 0x20); + } +} + +asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs) +{ + struct irqaction *action; + int do_random, cpu; + + cpu = smp_processor_id(); + irq_enter(cpu, irq); + + if (irq >= 16) + goto out; + + i8259_mask_and_ack_irq(irq); + + kstat.irqs[cpu][irq]++; + + action = *(irq + irq_action); + if (!action) + goto out; + + if (!(action->flags & SA_INTERRUPT)) + __sti(); + action = *(irq + irq_action); + do_random = 0; + do { + do_random |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (do_random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + __cli(); + unmask_irq (irq); + +out: + irq_exit(cpu, irq); +} + +/* + * do_IRQ handles IRQ's that have been installed without the + * SA_INTERRUPT flag: it uses the full signal-handling return + * and runs with other interrupts enabled. All relatively slow + * IRQ's should use this format: notably the keyboard/timer + * routines. + */ +asmlinkage void do_IRQ(int irq, struct pt_regs * regs) +{ + struct irqaction *action; + int do_random, cpu; + + cpu = smp_processor_id(); + irq_enter(cpu, irq); + kstat.irqs[cpu][irq]++; + + action = *(irq + irq_action); + if (action) { + if (!(action->flags & SA_INTERRUPT)) + __sti(); + action = *(irq + irq_action); + do_random = 0; + do { + do_random |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (do_random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + __cli(); + } + irq_exit(cpu, irq); + + if (softirq_active(cpu)&softirq_mask(cpu)) + do_softirq(); + + /* unmasking and bottom half handling is done magically for us. */ +} + +int i8259_setup_irq(int irq, struct irqaction * new) +{ + int shared = 0; + struct irqaction *old, **p; + unsigned long flags; + + p = irq_action + irq; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) + return -EBUSY; + + /* Can't share interrupts unless both are same type */ + if ((old->flags ^ new->flags) & SA_INTERRUPT) + return -EBUSY; + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + if (new->flags & SA_SAMPLE_RANDOM) + rand_initialize_irq(irq); + + save_and_cli(flags); + *p = new; + + if (!shared) { + if (is_i8259_irq(irq)) + unmask_irq(irq); +#if (defined(CONFIG_DDB5074) || defined(CONFIG_DDB5476)) + else + nile4_enable_irq(irq_to_nile4(irq)); +#endif + } + restore_flags(flags); + return 0; +} + +/* + * Request_interrupt and free_interrupt ``sort of'' handle interrupts of + * non i8259 devices. They will have to be replaced by architecture + * specific variants. For now we still use this as broken as it is because + * it used to work ... + */ +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char * devname, void *dev_id) +{ + int retval; + struct irqaction * action; + + if (irq >= 32) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = i8259_setup_irq(irq, action); + + if (retval) + kfree(action); + return retval; +} + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction * action, **p; + unsigned long flags; + + if (irq > 31) { + printk("Trying to free IRQ%d\n",irq); + return; + } + for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { + if (action->dev_id != dev_id) + continue; + + /* Found it - now free it */ + save_and_cli(flags); + *p = action->next; + if (!irq[irq_action]) + mask_irq(irq); + restore_flags(flags); + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n",irq); +} + +unsigned long probe_irq_on (void) +{ + unsigned int i, irqs = 0; + unsigned long delay; + + /* first, enable any unassigned (E)ISA irqs */ + for (i = 15; i > 0; i--) { + if (!irq_action[i]) { + i8259_enable_irq(i); + irqs |= (1 << i); + } + } + + /* wait for spurious interrupts to mask themselves out again */ + for (delay = jiffies + HZ/10; time_before(jiffies, delay); ) + /* about 100ms delay */; + + /* now filter out any obviously spurious interrupts */ + return irqs & ~cached_irq_mask; +} + +int probe_irq_off (unsigned long irqs) +{ + unsigned int i; + +#ifdef DEBUG + printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask); +#endif + irqs &= cached_irq_mask; + if (!irqs) + return 0; + i = ffz(~irqs); + if (irqs != (irqs & (1 << i))) + i = -i; + return i; +} + +void __init i8259_init(void) +{ + /* Init master interrupt controller */ + outb(0x11, 0x20); /* Start init sequence */ + outb(0x00, 0x21); /* Vector base */ + outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */ + outb(0x01, 0x21); /* Select 8086 mode */ + outb(0xff, 0x21); /* Mask all */ + + /* Init slave interrupt controller */ + outb(0x11, 0xa0); /* Start init sequence */ + outb(0x08, 0xa1); /* Vector base */ + outb(0x02, 0xa1); /* edge triggered, Cascade (slave) on IRQ2 */ + outb(0x01, 0xa1); /* Select 8086 mode */ + outb(0xff, 0xa1); /* Mask all */ + + outb(cached_A1, 0xa1); + outb(cached_21, 0x21); +} + +void __init init_IRQ(void) +{ + /* i8259_init(); */ + irq_setup(); +} diff --git a/arch/mips/kernel/old-time.c b/arch/mips/kernel/old-time.c new file mode 100644 index 000000000000..d42ff610ea6f --- /dev/null +++ b/arch/mips/kernel/old-time.c @@ -0,0 +1,519 @@ +/* + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * Copyright (C) 1996 - 2000 Ralf Baechle + * + * This file contains the time handling details for PC-style clocks as + * found in some MIPS systems. + */ +/************************************************************************** + * 9 Nov, 2000. + * Changed init_cycle_counter() routine, use the mips_cpu structure. + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ + +#include <linux/config.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/kernel_stat.h> + +#include <asm/bootinfo.h> +#include <asm/cpu.h> +#include <asm/mipsregs.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/ddb5074.h> + +#include <linux/mc146818rtc.h> +#include <linux/timex.h> + +extern volatile unsigned long wall_jiffies; +unsigned long r4k_interval; +extern rwlock_t xtime_lock; + +/* + * Change this if you have some constant time drift + */ +/* This is the value for the PC-style PICs. */ +/* #define USECS_PER_JIFFY (1000020/HZ) */ + +/* This is for machines which generate the exact clock. */ +#define USECS_PER_JIFFY (1000000/HZ) + +/* Cycle counter value at the previous timer interrupt.. */ + +static unsigned int timerhi, timerlo; + +/* + * On MIPS only R4000 and better have a cycle counter. + * + * FIXME: Does playing with the RP bit in c0_status interfere with this code? + */ +static unsigned long do_fast_gettimeoffset(void) +{ + u32 count; + unsigned long res, tmp; + + /* Last jiffy when do_fast_gettimeoffset() was called. */ + static unsigned long last_jiffies; + unsigned long quotient; + + /* + * Cached "1/(clocks per usec)*2^32" value. + * It has to be recalculated once each jiffy. + */ + static unsigned long cached_quotient; + + tmp = jiffies; + + quotient = cached_quotient; + + if (tmp && last_jiffies != tmp) { + last_jiffies = tmp; + __asm__(".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "lwu\t%0,%2\n\t" + "dsll32\t$1,%1,0\n\t" + "or\t$1,$1,%0\n\t" + "ddivu\t$0,$1,%3\n\t" + "mflo\t$1\n\t" + "dsll32\t%0,%4,0\n\t" + "nop\n\t" + "ddivu\t$0,%0,$1\n\t" + "mflo\t%0\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=&r" (quotient) + :"r" (timerhi), + "m" (timerlo), + "r" (tmp), + "r" (USECS_PER_JIFFY) + :"$1"); + cached_quotient = quotient; + } + + /* Get last timer tick in absolute kernel time */ + count = read_32bit_cp0_register(CP0_COUNT); + + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; + + __asm__("multu\t%1,%2\n\t" + "mfhi\t%0" + :"=r" (res) + :"r" (count), + "r" (quotient)); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY-1; + + return res; +} + +/* This function must be called with interrupts disabled + * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs + * + * However, the pc-audio speaker driver changes the divisor so that + * it gets interrupted rather more often - it loads 64 into the + * counter rather than 11932! This has an adverse impact on + * do_gettimeoffset() -- it stops working! What is also not + * good is that the interval that our timer function gets called + * is no longer 10.0002 ms, but 9.9767 ms. To get around this + * would require using a different timing source. Maybe someone + * could use the RTC - I know that this can interrupt at frequencies + * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix + * it so that at startup, the timer code in sched.c would select + * using either the RTC or the 8253 timer. The decision would be + * based on whether there was any other device around that needed + * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz, + * and then do some jiggery to have a version of do_timer that + * advanced the clock by 1/1024 s. Every time that reached over 1/100 + * of a second, then do all the old code. If the time was kept correct + * then do_gettimeoffset could just return 0 - there is no low order + * divider that can be accessed. + * + * Ideally, you would be able to use the RTC for the speaker driver, + * but it appears that the speaker driver really needs interrupt more + * often than every 120 us or so. + * + * Anyway, this needs more thought.... pjsg (1993-08-28) + * + * If you are really that interested, you should be reading + * comp.protocols.time.ntp! + */ + +#define TICK_SIZE tick + +static unsigned long do_slow_gettimeoffset(void) +{ + int count; + + static int count_p = LATCH; /* for the first call after boot */ + static unsigned long jiffies_p; + + /* + * cache volatile jiffies temporarily; we have IRQs turned off. + */ + unsigned long jiffies_t; + + /* timer count may underflow right here */ + outb_p(0x00, 0x43); /* latch the count ASAP */ + + count = inb_p(0x40); /* read the latched count */ + + /* + * We do this guaranteed double memory access instead of a _p + * postfix in the previous port access. Wheee, hackady hack + */ + jiffies_t = jiffies; + + count |= inb_p(0x40) << 8; + + /* + * avoiding timer inconsistencies (they are rare, but they happen)... + * there are two kinds of problems that must be avoided here: + * 1. the timer counter underflows + * 2. hardware problem with the timer, not giving us continuous time, + * the counter does small "jumps" upwards on some Pentium systems, + * (see c't 95/10 page 335 for Neptun bug.) + */ + + if( jiffies_t == jiffies_p ) { + if( count > count_p ) { + /* the nutcase */ + + outb_p(0x0A, 0x20); + + /* assumption about timer being IRQ1 */ + if (inb(0x20) & 0x01) { + /* + * We cannot detect lost timer interrupts ... + * well, that's why we call them lost, don't we? :) + * [hmm, on the Pentium and Alpha we can ... sort of] + */ + count -= LATCH; + } else { + printk("do_slow_gettimeoffset(): hardware timer problem?\n"); + } + } + } else + jiffies_p = jiffies_t; + + count_p = count; + + count = ((LATCH-1) - count) * TICK_SIZE; + count = (count + LATCH/2) / LATCH; + + return count; +} + +static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; + +/* + * This version of gettimeofday has near microsecond resolution. + */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + + read_lock_irqsave (&xtime_lock, flags); + *tv = xtime; + tv->tv_usec += do_gettimeoffset(); + + /* + * xtime is atomically updated in timer_bh. jiffies - wall_jiffies + * is nonzero if the timer bottom half hasnt executed yet. + */ + if (jiffies - wall_jiffies) + tv->tv_usec += USECS_PER_JIFFY; + + read_unlock_irqrestore (&xtime_lock, flags); + + if (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } +} + +void do_settimeofday(struct timeval *tv) +{ + write_lock_irq (&xtime_lock); + + /* This is revolting. We need to set the xtime.tv_usec + * correctly. However, the value in this location is + * is value at the last tick. + * Discover what correction gettimeofday + * would have done, and then undo it! + */ + tv->tv_usec -= do_gettimeoffset(); + + if (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + xtime = *tv; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + + write_unlock_irq (&xtime_lock); +} + +/* + * In order to set the CMOS clock precisely, set_rtc_mmss has to be + * called 500 ms after the second nowtime has started, because when + * nowtime is written into the registers of the CMOS clock, it will + * jump to the next second precisely 500 ms later. Check the Motorola + * MC146818A or Dallas DS12887 data sheet for details. + * + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you won't notice until after reboot! + */ +static int set_rtc_mmss(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; + + save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + cmos_minutes = CMOS_READ(RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + BCD_TO_BIN(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + } + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + return retval; +} + +/* last time the cmos clock got updated */ +static long last_rtc_update; + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ +static void inline +timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ +#ifdef CONFIG_DDB5074 + static unsigned cnt, period, dist; + + if (cnt == 0 || cnt == dist) + ddb5074_led_d2(1); + else if (cnt == 7 || cnt == dist+7) + ddb5074_led_d2(0); + + if (++cnt > period) { + cnt = 0; + /* The hyperbolic function below modifies the heartbeat period + * length in dependency of the current (5min) load. It goes + * through the points f(0)=126, f(1)=86, f(5)=51, + * f(inf)->30. */ + period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; + dist = period / 4; + } +#endif + if(!user_mode(regs)) { + if (prof_buffer && current->pid) { + extern int _stext; + unsigned long pc = regs->cp0_epc; + + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + /* + * Dont ignore out-of-bounds pc values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + if (pc > prof_len-1) + pc = prof_len-1; + atomic_inc((atomic_t *)&prof_buffer[pc]); + } + } + do_timer(regs); + + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + read_lock (&xtime_lock); + if ((time_status & STA_UNSYNC) == 0 && + xtime.tv_sec > last_rtc_update + 660 && + xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 && + xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) { + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + } + /* As we return to user mode fire off the other CPU schedulers.. this is + basically because we don't yet share IRQ's around. This message is + rigged to be safe on the 386 - basically it's a hack, so don't look + closely for now.. */ + /*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */ + read_unlock (&xtime_lock); +} + +static inline void +r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + unsigned int count; + + /* + * The cycle counter is only 32 bit which is good for about + * a minute at current count rates of upto 150MHz or so. + */ + count = read_32bit_cp0_register(CP0_COUNT); + timerhi += (count < timerlo); /* Wrap around */ + timerlo = count; + +#ifdef CONFIG_SGI_IP22 + /* Since we don't get anything but r4k timer interrupts, we need to + * set this up so that we'll get one next time. Fortunately since we + * have timerhi/timerlo, we don't care so much if we miss one. So + * we need only ask for the next in r4k_interval counts. On other + * archs we have a real timer, so we don't want this. + */ + write_32bit_cp0_register (CP0_COMPARE, + (unsigned long) (count + r4k_interval)); + kstat.irqs[0][irq]++; +#endif + + timer_interrupt(irq, dev_id, regs); + + if (!jiffies) + { + /* + * If jiffies has overflowed in this timer_interrupt we must + * update the timer[hi]/[lo] to make do_fast_gettimeoffset() + * quotient calc still valid. -arca + */ + timerhi = timerlo = 0; + } +} + +void indy_r4k_timer_interrupt (struct pt_regs *regs) +{ + static const int INDY_R4K_TIMER_IRQ = 7; + r4k_timer_interrupt (INDY_R4K_TIMER_IRQ, NULL, regs); +} + +struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, + "timer", NULL, NULL}; + + +void (*board_time_init)(struct irqaction *irq); + +void __init time_init(void) +{ + unsigned int epoch = 0, year, mon, day, hour, min, sec; + int i; + + /* The Linux interpretation of the CMOS clock register contents: + * When the Update-In-Progress (UIP) flag goes from 1 to 0, the + * RTC registers show the second which has precisely just started. + * Let's hope other operating systems interpret the RTC the same way. + */ + /* read RTC exactly on falling edge of update flag */ + for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ + if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) + break; + for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ + if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) + break; + do { /* Isn't this overkill ? UIP above should guarantee consistency */ + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + } while (sec != CMOS_READ(RTC_SECONDS)); + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + + /* Attempt to guess the epoch. This is the same heuristic as in rtc.c so + no stupid things will happen to timekeeping. Who knows, maybe Ultrix + also uses 1952 as epoch ... */ + if (year > 10 && year < 44) { + epoch = 1980; + } else if (year < 96) { + epoch = 1952; + } + year += epoch; + + write_lock_irq (&xtime_lock); + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + xtime.tv_usec = 0; + write_unlock_irq (&xtime_lock); + + if (mips_cpu.options & MIPS_CPU_COUNTER) { + write_32bit_cp0_register(CP0_COUNT, 0); + do_gettimeoffset = do_fast_gettimeoffset; + irq0.handler = r4k_timer_interrupt; + } + + board_time_init(&irq0); +} diff --git a/arch/mips/kernel/pci-dma.c b/arch/mips/kernel/pci-dma.c new file mode 100644 index 000000000000..6efed2e1b37e --- /dev/null +++ b/arch/mips/kernel/pci-dma.c @@ -0,0 +1,41 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com> + * Copyright (C) 2000 Ralf Baechle <ralf@gnu.org> + * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. + */ +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/pci.h> + +#include <asm/io.h> + +void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t * dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC; + + if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) + gfp |= GFP_DMA; + ret = (void *) __get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + dma_cache_wback_inv((unsigned long) ret, size); + *dma_handle = virt_to_bus(ret); + ret = KSEG1ADDR(ret); + } + + return ret; +} + +void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + free_pages((unsigned long) KSEG0ADDR(vaddr), get_order(size)); +} diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 701321a6bee2..773d72c0d816 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -7,12 +7,16 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <asm/bootinfo.h> +#include <asm/cpu.h> #include <asm/mipsregs.h> #include <asm/processor.h> #include <asm/watch.h> unsigned long unaligned_instructions; unsigned int vced_count, vcei_count; +#if !defined(CONFIG_CPU_HAS_LLSC) +unsigned long ll_ops, sc_ops; +#endif /* * BUFFER is PAGE_SIZE bytes long. @@ -35,32 +39,37 @@ int get_cpuinfo(char *buffer) const char *mach_cobalt_names[] = GROUP_COBALT_NAMES; const char *mach_nec_ddb_names[] = GROUP_NEC_DDB_NAMES; const char *mach_baget_names[] = GROUP_BAGET_NAMES; + const char *mach_cosine_names[] = GROUP_COSINE_NAMES; + const char *mach_galileo_names[] = GROUP_GALILEO_NAMES; + const char *mach_momenco_names[] = GROUP_MOMENCO_NAMES; + const char *mach_ite_names[] = GROUP_ITE_NAMES; + const char *mach_philips_names[] = GROUP_PHILIPS_NAMES; + const char *mach_globespan_names[] = GROUP_GLOBESPAN_NAMES; + const char *mach_sibyte_names[] = GROUP_SIBYTE_NAMES; + const char *mach_toshiba_names[] = GROUP_TOSHIBA_NAMES; + const char *mach_alchemy_names[] = GROUP_ALCHEMY_NAMES; const char **mach_group_to_name[] = { mach_unknown_names, - mach_jazz_names, - mach_dec_names, - mach_arc_names, - mach_sni_rm_names, - mach_acn_names, - mach_sgi_names, - mach_cobalt_names, - mach_nec_ddb_names, - mach_baget_names }; + mach_jazz_names, mach_dec_names, mach_arc_names, + mach_sni_rm_names, mach_acn_names, mach_sgi_names, + mach_cobalt_names, mach_nec_ddb_names, mach_baget_names, + mach_cosine_names, mach_galileo_names, mach_momenco_names, + mach_ite_names, mach_philips_names, mach_globespan_names, + mach_sibyte_names, mach_toshiba_names, mach_alchemy_names}; unsigned int version = read_32bit_cp0_register(CP0_PRID); int len; len = sprintf(buffer, "cpu\t\t\t: MIPS\n"); len += sprintf(buffer + len, "cpu model\t\t: %s V%d.%d\n", - cpu_name[mips_cputype <= CPU_LAST ? - mips_cputype : - CPU_UNKNOWN], - (version >> 4) & 0x0f, - version & 0x0f); + cpu_name[mips_cpu.cputype <= CPU_LAST ? + mips_cpu.cputype : CPU_UNKNOWN], + (version >> 4) & 0x0f, version & 0x0f); len += sprintf(buffer + len, "system type\t\t: %s %s\n", mach_group_names[mips_machgroup], mach_group_to_name[mips_machgroup][mips_machtype]); len += sprintf(buffer + len, "BogoMIPS\t\t: %lu.%02lu\n", - (loops_per_sec + 2500) / 500000, - ((loops_per_sec + 2500) / 5000) % 100); + loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100); + #if defined (__MIPSEB__) len += sprintf(buffer + len, "byteorder\t\t: big endian\n"); #endif @@ -72,17 +81,23 @@ int get_cpuinfo(char *buffer) len += sprintf(buffer + len, "wait instruction\t: %s\n", cpu_wait ? "yes" : "no"); len += sprintf(buffer + len, "microsecond timers\t: %s\n", - cyclecounter_available ? "yes" : "no"); + (mips_cpu.options & MIPS_CPU_COUNTER) ? "yes" : "no"); len += sprintf(buffer + len, "extra interrupt vector\t: %s\n", dedicated_iv_available ? "yes" : "no"); len += sprintf(buffer + len, "hardware watchpoint\t: %s\n", watch_available ? "yes" : "no"); sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", - vce_available ? "%d" : "not available"); + (mips_cpu.options & MIPS_CPU_VCE) ? "%d" : "not available"); len += sprintf(buffer + len, fmt, 'D', vced_count); len += sprintf(buffer + len, fmt, 'I', vcei_count); +#if !defined(CONFIG_CPU_HAS_LLSC) + len += sprintf(buffer + len, "ll emulations\t\t: %lu\n", + ll_ops); + len += sprintf(buffer + len, "sc emulations\t\t: %lu\n", + sc_ops); +#endif return len; } diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index a4a239e73f6c..9284db514108 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -162,21 +162,21 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) long retval; __asm__ __volatile__( - ".set\tnoreorder\n\t" - "move\t$6,$sp\n\t" - "move\t$4,%5\n\t" - "li\t$2,%1\n\t" - "syscall\n\t" - "beq\t$6,$sp,1f\n\t" - "subu\t$sp,32\n\t" /* delay slot */ - "jalr\t%4\n\t" - "move\t$4,%3\n\t" /* delay slot */ - "move\t$4,$2\n\t" - "li\t$2,%2\n\t" - "syscall\n" - "1:\taddiu\t$sp,32\n\t" - "move\t%0,$2\n\t" - ".set\treorder" + ".set noreorder \n" + " move $6,$sp \n" + " move $4,%5 \n" + " li $2,%1 \n" + " syscall \n" + " beq $6,$sp,1f \n" + " subu $sp,32 \n" /* delay slot */ + " jalr %4 \n" + " move $4,%3 \n" /* delay slot */ + " move $4,$2 \n" + " li $2,%2 \n" + " syscall \n" + "1: addiu $sp,32 \n" + " move %0,$2 \n" + ".set reorder" :"=r" (retval) :"i" (__NR_clone), "i" (__NR_exit), "r" (arg), "r" (fn), @@ -199,27 +199,47 @@ extern void scheduling_functions_end_here(void); #define first_sched ((unsigned long) scheduling_functions_start_here) #define last_sched ((unsigned long) scheduling_functions_end_here) +/* get_wchan - a maintenance nightmare ... */ unsigned long get_wchan(struct task_struct *p) { - unsigned long schedule_frame; - unsigned long pc; + unsigned long frame, pc; if (!p || p == current || p->state == TASK_RUNNING) return 0; pc = thread_saved_pc(&p->thread); - if (pc == (unsigned long) interruptible_sleep_on - || pc == (unsigned long) sleep_on) { - schedule_frame = ((unsigned long *)p->thread.reg30)[9]; - return ((unsigned long *)schedule_frame)[15]; - } - if (pc == (unsigned long) interruptible_sleep_on_timeout - || pc == (unsigned long) sleep_on_timeout) { - schedule_frame = ((unsigned long *)p->thread.reg30)[9]; - return ((unsigned long *)schedule_frame)[16]; + if (pc < first_sched || pc >= last_sched) { + return pc; } + + if (pc >= (unsigned long) sleep_on_timeout) + goto schedule_timeout_caller; + if (pc >= (unsigned long) sleep_on) + goto schedule_caller; + if (pc >= (unsigned long) interruptible_sleep_on_timeout) + goto schedule_timeout_caller; + if (pc >= (unsigned long)interruptible_sleep_on) + goto schedule_caller; + goto schedule_timeout_caller; + +schedule_caller: + frame = ((unsigned long *)p->thread.reg30)[9]; + pc = ((unsigned long *)frame)[11]; + return pc; + +schedule_timeout_caller: + /* Must be schedule_timeout ... */ + pc = ((unsigned long *)p->thread.reg30)[10]; + frame = ((unsigned long *)p->thread.reg30)[9]; + + /* The schedule_timeout frame ... */ + pc = ((unsigned long *)frame)[14]; + frame = ((unsigned long *)frame)[13]; + if (pc >= first_sched && pc < last_sched) { - printk(KERN_DEBUG "Bug in %s\n", __FUNCTION__); + /* schedule_timeout called by interruptible_sleep_on_timeout */ + pc = ((unsigned long *)frame)[11]; + frame = ((unsigned long *)frame)[10]; } return pc; diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index f042b6947740..06c3ad657ac0 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -207,7 +207,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_POKEUSR: { struct pt_regs *regs; - int res = 0; + res = 0; regs = (struct pt_regs *) ((unsigned long) child + KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs)); @@ -289,7 +289,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) */ case PTRACE_KILL: res = 0; - if (child->state != TASK_ZOMBIE) /* already dead */ + if (child->state == TASK_ZOMBIE) /* already dead */ break; child->exit_code = SIGKILL; wake_up_process(child); @@ -299,7 +299,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) res = -EIO; if ((unsigned long) data > _NSIG) break; - child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); + child->ptrace = 0; child->exit_code = data; write_lock_irq(&tasklist_lock); REMOVE_LINKS(child); @@ -310,6 +310,14 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) res = 0; break; + case PTRACE_SETOPTIONS: + if (data & PTRACE_O_TRACESYSGOOD) + child->ptrace |= PT_TRACESYSGOOD; + else + child->ptrace &= ~PT_TRACESYSGOOD; + res = 0; + break; + default: res = -EIO; goto out; @@ -326,7 +334,10 @@ asmlinkage void syscall_trace(void) if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) != (PT_PTRACED|PT_TRACESYS)) return; - current->exit_code = SIGTRAP; + /* The 0x80 provides a way for the tracing parent to distinguish + between a syscall stop and SIGTRAP delivery */ + current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0); current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); diff --git a/arch/mips/kernel/r2300_fpu.S b/arch/mips/kernel/r2300_fpu.S index 5489ea9b89b7..f83c31f720c4 100644 --- a/arch/mips/kernel/r2300_fpu.S +++ b/arch/mips/kernel/r2300_fpu.S @@ -117,6 +117,7 @@ LEAF(_restore_fp_context) jr ra ctc1 t0,fcr31 END(_restore_fp_context) + .set reorder .type fault@function .ent fault diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S index 4a546ebb509f..a17873ab50ee 100644 --- a/arch/mips/kernel/r2300_switch.S +++ b/arch/mips/kernel/r2300_switch.S @@ -34,6 +34,9 @@ * task_struct *next) */ LEAF(resume) +#ifndef CONFIG_CPU_HAS_LLSC + sw zero, ll_bit +#endif mfc0 t1, CP0_STATUS sw t1, THREAD_STATUS(a0) CPU_SAVE_NONSCRATCH(a0) diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 6ad810d04d24..b1f1fdcc21fa 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -93,6 +93,7 @@ LEAF(_restore_fp_context) jr ra ctc1 t0,fcr31 END(_restore_fp_context) + .set reorder .type fault@function .ent fault diff --git a/arch/mips/kernel/r4k_misc.S b/arch/mips/kernel/r4k_misc.S index bfa3cb82cb48..e16820f889c0 100644 --- a/arch/mips/kernel/r4k_misc.S +++ b/arch/mips/kernel/r4k_misc.S @@ -35,10 +35,25 @@ * in register PTE, a ptr into the table in which * the pte belongs is in PTR. */ + +#ifdef CONFIG_SMP +#define GET_PGD(scratch, ptr) \ + mfc0 ptr, CP0_CONTEXT; \ + la scratch, current_pgd;\ + srl ptr, 23; \ + sll ptr, 2; \ + addu ptr, scratch, ptr; \ + lw ptr, (ptr); +#else +#define GET_PGD(scratch, ptr) \ + lw ptr, current_pgd; +#endif + + #define LOAD_PTE(pte, ptr) \ + GET_PGD(pte, ptr) \ mfc0 pte, CP0_BADVADDR; \ srl pte, pte, 22; \ - lw ptr, current_pgd; \ sll pte, pte, 2; \ addu ptr, ptr, pte; \ mfc0 pte, CP0_BADVADDR; \ diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index e1d10f92d572..140adcbebfa0 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -1,5 +1,4 @@ -/* $Id: r4k_switch.S,v 1.9 1999/08/18 23:37:44 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -38,6 +37,9 @@ .set noreorder .align 5 LEAF(resume) +#ifndef CONFIG_CPU_HAS_LLSC + sw zero, ll_bit +#endif mfc0 t1, CP0_STATUS sw t1, THREAD_STATUS(a0) CPU_SAVE_NONSCRATCH(a0) @@ -50,7 +52,16 @@ move $28, a1 CPU_RESTORE_NONSCRATCH($28) addiu t0, $28, KERNEL_STACK_SIZE-32 +#ifdef CONFIG_SMP + mfc0 a3, CP0_CONTEXT + la t1, kernelsp + srl a3, 23 + sll a3, 2 + addu t1, a3, t1 + sw t0, (t1) +#else sw t0, kernelsp +#endif mfc0 t1, CP0_STATUS /* Do we really need this? */ li a3, 0xff00 and t1, a3 diff --git a/arch/mips/kernel/scall_o32.S b/arch/mips/kernel/scall_o32.S index bdc72ca4ee21..d7c107599c7b 100644 --- a/arch/mips/kernel/scall_o32.S +++ b/arch/mips/kernel/scall_o32.S @@ -65,8 +65,14 @@ stack_done: 1: sw v0, PT_R2(sp) # result EXPORT(o32_ret_from_sys_call) - lw t0, irq_stat # softirq_active - lw t1, irq_stat+4 # softirq_mask. unused delay slot + la t1, irq_stat # softirq_active +#ifdef CONFIG_SMP + lw t0, TASK_PROCESSOR($28) + sll t0, t0, 5 + addu t1, t0 +#endif + lw t0, 0(t1) # softirq_active + lw t1, 4(t1) # softirq_mask. unused delay slot and t0, t1 bnez t0, o32_handle_softirq diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 2a6bdbce40c1..c9e6ec63b308 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -26,13 +26,9 @@ #include <linux/a.out.h> #include <linux/tty.h> #include <linux/bootmem.h> -#ifdef CONFIG_BLK_DEV_RAM #include <linux/blk.h> -#endif #include <linux/ide.h> -#ifdef CONFIG_RTC #include <linux/timex.h> -#endif #include <asm/asm.h> #include <asm/bootinfo.h> @@ -45,7 +41,8 @@ #include <asm/sgialib.h> #endif -struct mips_cpuinfo boot_cpu_data = { NULL, NULL, 0 }; + +struct mips_cpuinfo boot_cpu_data = { 0, NULL, NULL, 0 }; /* * Not all of the MIPS CPUs have the "wait" instruction available. Moreover, @@ -57,11 +54,6 @@ struct mips_cpuinfo boot_cpu_data = { NULL, NULL, 0 }; void (*cpu_wait)(void) = NULL; /* - * Do we have a cyclecounter available? - */ -char cyclecounter_available; - -/* * There are several bus types available for MIPS machines. "RISC PC" * type machines have ISA, EISA, VLB or PCI available, DECstations * have Turbochannel or Q-Bus, SGI has GIO, there are lots of VME @@ -72,16 +64,16 @@ int EISA_bus = 0; struct screen_info screen_info; -#ifdef CONFIG_BLK_DEV_FD extern struct fd_ops no_fd_ops; struct fd_ops *fd_ops; -#endif #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) extern struct ide_ops no_ide_ops; struct ide_ops *ide_ops; #endif +extern void * __rd_start, * __rd_end; + extern struct rtc_ops no_rtc_ops; struct rtc_ops *rtc_ops; @@ -95,23 +87,17 @@ struct kbd_ops *kbd_ops; * * These are initialized so they are in the .data section */ -unsigned long mips_memory_upper = KSEG0; /* this is set by kernel_entry() */ -unsigned long mips_cputype = CPU_UNKNOWN; unsigned long mips_machtype = MACH_UNKNOWN; unsigned long mips_machgroup = MACH_GROUP_UNKNOWN; +struct boot_mem_map boot_mem_map; + unsigned char aux_device_present; -extern int _end; +extern char _ftext, _etext, _fdata, _edata, _end; -static char command_line[CL_SIZE] = { 0, }; - char saved_command_line[CL_SIZE]; -extern char arcs_cmdline[CL_SIZE]; - -/* - * The board specific setup routine sets irq_setup to point to a board - * specific setup routine. - */ -void (*irq_setup)(void); +static char command_line[COMMAND_LINE_SIZE]; + char saved_command_line[COMMAND_LINE_SIZE]; +extern char arcs_cmdline[COMMAND_LINE_SIZE]; /* * mips_io_port_base is the begin of the address space to which x86 style @@ -129,7 +115,10 @@ extern void sgi_sysinit(void); extern void SetUpBootInfo(void); extern void loadmmu(void); extern asmlinkage void start_kernel(void); -extern int prom_init(int, char **, char **, int *); +extern void prom_init(int, char **, char **, int *); + +static struct resource code_resource = { "Kernel code" }; +static struct resource data_resource = { "Kernel data" }; /* * Probe whether cpu has config register by trying to play with @@ -143,9 +132,9 @@ static inline int cpu_has_confreg(void) unsigned long size1, size2; unsigned long cfg = read_32bit_cp0_register(CP0_CONF); - size1 = r3k_cache_size(ST0_DE); + size1 = r3k_cache_size(ST0_ISC); write_32bit_cp0_register(CP0_CONF, cfg^CONF_AC); - size2 = r3k_cache_size(ST0_DE); + size2 = r3k_cache_size(ST0_ISC); write_32bit_cp0_register(CP0_CONF, cfg); return size1 != size2; #else @@ -165,152 +154,230 @@ int *cpuoptions = &mips_cpu.options; static inline void cpu_probe(void) { + +#ifdef CONFIG_CPU_MIPS32 unsigned long config1; +#endif mips_cpu.processor_id = read_32bit_cp0_register(CP0_PRID); - switch (mips_cpu.processor_id & 0xff00) { - case PRID_IMP_R2000: - mips_cpu.cputype = CPU_R2000; - mips_cpu.isa_level = MIPS_CPU_ISA_I; - mips_cpu.options = MIPS_CPU_TLB; - mips_cpu.tlbsize = 64; - break; - case PRID_IMP_R3000: - if ((mips_cpu.processor_id & 0xff) == PRID_REV_R3000A) - if (cpu_has_confreg()) - mips_cpu.cputype = CPU_R3081E; + switch (mips_cpu.processor_id & 0xff0000) { + case PRID_COMP_LEGACY: + switch (mips_cpu.processor_id & 0xff00) { + case PRID_IMP_R2000: + mips_cpu.cputype = CPU_R2000; + mips_cpu.isa_level = MIPS_CPU_ISA_I; + mips_cpu.options = MIPS_CPU_TLB; + mips_cpu.tlbsize = 64; + break; + case PRID_IMP_R3000: + if ((mips_cpu.processor_id & 0xff) == PRID_REV_R3000A) + if (cpu_has_confreg()) + mips_cpu.cputype = CPU_R3081E; + else + mips_cpu.cputype = CPU_R3000A; else - mips_cpu.cputype = CPU_R3000A; - else - mips_cpu.cputype = CPU_R3000; - mips_cpu.isa_level = MIPS_CPU_ISA_I; - mips_cpu.options = MIPS_CPU_TLB; - mips_cpu.tlbsize = 64; - break; - case PRID_IMP_R4000: - if ((mips_cpu.processor_id & 0xff) == PRID_REV_R4400) - mips_cpu.cputype = CPU_R4400SC; - else - mips_cpu.cputype = CPU_R4000SC; - mips_cpu.isa_level = MIPS_CPU_ISA_III; - mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_WATCH | MIPS_CPU_VCE; - mips_cpu.tlbsize = 48; - break; - case PRID_IMP_R4600: - mips_cpu.cputype = CPU_R4600; - mips_cpu.isa_level = MIPS_CPU_ISA_III; - mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU; - mips_cpu.tlbsize = 48; - break; + mips_cpu.cputype = CPU_R3000; + mips_cpu.isa_level = MIPS_CPU_ISA_I; + mips_cpu.options = MIPS_CPU_TLB; + mips_cpu.tlbsize = 64; + break; + case PRID_IMP_R4000: + if ((mips_cpu.processor_id & 0xff) == PRID_REV_R4400) + mips_cpu.cputype = CPU_R4400SC; + else + mips_cpu.cputype = CPU_R4000SC; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_WATCH | MIPS_CPU_VCE; + mips_cpu.tlbsize = 48; + break; + case PRID_IMP_R4600: + mips_cpu.cputype = CPU_R4600; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU; + mips_cpu.tlbsize = 48; + break; /* * This processor doesn't have an MMU, so it's not "real easy" to * run Linux on it. It is left purely for documentation. - * - case PRID_IMP_R4650: - mips_cpu.cputype = CPU_R4650; - mips_cpu.isa_level = MIPS_CPU_ISA_III; - mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU; - mips_cpu.tlbsize = 48; + * case PRID_IMP_R4650: + mips_cpu.cputype = CPU_R4650; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU; + mips_cpu.tlbsize = 48; + break; +*/ + case PRID_IMP_TX39: + mips_cpu.isa_level = MIPS_CPU_ISA_I; + mips_cpu.options = MIPS_CPU_TLB; + + switch (mips_cpu.processor_id & 0xff) { + case PRID_REV_TX3912: + mips_cpu.cputype = CPU_TX3912; + mips_cpu.tlbsize = 32; + break; + case PRID_REV_TX3922: + mips_cpu.cputype = CPU_TX3922; + mips_cpu.tlbsize = 64; + break; + case PRID_REV_TX3927: + mips_cpu.cputype = CPU_TX3927; + mips_cpu.tlbsize = 64; + break; + default: + mips_cpu.cputype = CPU_UNKNOWN; + break; + } + break; + case PRID_IMP_R4700: + mips_cpu.cputype = CPU_R4700; + mips_cpu.isa_level = MIPS_CPU_ISA_III; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 48; + break; + case PRID_IMP_R5000: + mips_cpu.cputype = CPU_R5000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 48; + break; + case PRID_IMP_R5432: + mips_cpu.cputype = CPU_R5432; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 48; + break; + case PRID_IMP_NEVADA: + mips_cpu.cputype = CPU_NEVADA; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_DIVEC; + mips_cpu.tlbsize = 48; + mips_cpu.icache.ways = 2; + mips_cpu.dcache.ways = 2; + break; + case PRID_IMP_R6000: + mips_cpu.cputype = CPU_R6000; + mips_cpu.isa_level = MIPS_CPU_ISA_II; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU; + mips_cpu.tlbsize = 32; + break; + case PRID_IMP_R6000A: + mips_cpu.cputype = CPU_R6000A; + mips_cpu.isa_level = MIPS_CPU_ISA_II; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU; + mips_cpu.tlbsize = 32; + break; + case PRID_IMP_RM7000: + mips_cpu.cputype = CPU_RM7000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; + break; + case PRID_IMP_R8000: + mips_cpu.cputype = CPU_R8000; + mips_cpu.isa_level = MIPS_CPU_ISA_IV; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_FPU | MIPS_CPU_32FPR; + mips_cpu.tlbsize = 384; /* has wierd TLB: 3-way x 128 */ + break; + case PRID_IMP_R10000: + mips_cpu.cputype = CPU_R10000; + mips_cpu.cputype = MIPS_CPU_ISA_IV; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_COUNTER | MIPS_CPU_WATCH; + mips_cpu.tlbsize = 64; + break; + default: + mips_cpu.cputype = CPU_UNKNOWN; + break; + } break; - */ - case PRID_IMP_R3912: - mips_cpu.cputype = CPU_R3912; - mips_cpu.isa_level = MIPS_CPU_ISA_I; - mips_cpu.options = MIPS_CPU_TLB; - mips_cpu.tlbsize = 32; - break; - case PRID_IMP_R4700: - mips_cpu.cputype = CPU_R4700; - mips_cpu.isa_level = MIPS_CPU_ISA_III; - mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; - mips_cpu.tlbsize = 48; - break; - case PRID_IMP_R5000: - mips_cpu.cputype = CPU_R5000; - mips_cpu.isa_level = MIPS_CPU_ISA_IV; - mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; - mips_cpu.tlbsize = 48; - break; - case PRID_IMP_R5432: - mips_cpu.cputype = CPU_R5432; - mips_cpu.isa_level = MIPS_CPU_ISA_IV; - mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; - mips_cpu.tlbsize = 48; - break; - case PRID_IMP_NEVADA: - mips_cpu.cputype = CPU_NEVADA; - mips_cpu.isa_level = MIPS_CPU_ISA_IV; - mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_DIVEC; - mips_cpu.tlbsize = 48; - mips_cpu.icache.ways = 2; - mips_cpu.dcache.ways = 2; - break; - case PRID_IMP_R6000: - mips_cpu.cputype = CPU_R6000; - mips_cpu.isa_level = MIPS_CPU_ISA_II; - mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU; - mips_cpu.tlbsize = 32; - break; - case PRID_IMP_R6000A: - mips_cpu.cputype = CPU_R6000A; - mips_cpu.isa_level = MIPS_CPU_ISA_II; - mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU; - mips_cpu.tlbsize = 32; - break; - case PRID_IMP_RM7000: - mips_cpu.cputype = CPU_RM7000; - mips_cpu.isa_level = MIPS_CPU_ISA_IV; - mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR; - break; - case PRID_IMP_R8000: - mips_cpu.cputype = CPU_R8000; - mips_cpu.isa_level = MIPS_CPU_ISA_IV; - mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | - MIPS_CPU_FPU | MIPS_CPU_32FPR; - mips_cpu.tlbsize = 384; /* has wierd TLB: 3-way x 128 */ - break; - case PRID_IMP_R10000: - mips_cpu.cputype = CPU_R10000; - mips_cpu.isa_level = MIPS_CPU_ISA_IV; - mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | - MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_COUNTER | MIPS_CPU_WATCH; - mips_cpu.tlbsize = 64; +#ifdef CONFIG_CPU_MIPS32 + case PRID_COMP_MIPS: + switch (mips_cpu.processor_id & 0xff00) { + case PRID_IMP_4KC: + mips_cpu.cputype = CPU_4KC; + goto cpu_4kc; + case PRID_IMP_4KEC: + mips_cpu.cputype = CPU_4KEC; + goto cpu_4kc; + case PRID_IMP_4KSC: + mips_cpu.cputype = CPU_4KSC; +cpu_4kc: + /* Why do we set all these options by default, THEN query them?? */ + mips_cpu.cputype = MIPS_CPU_ISA_M32; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | + MIPS_CPU_DIVEC | MIPS_CPU_WATCH; + config1 = read_mips32_cp0_config1(); + if (config1 & (1 << 3)) + mips_cpu.options |= MIPS_CPU_WATCH; + if (config1 & (1 << 2)) + mips_cpu.options |= MIPS_CPU_MIPS16; + if (config1 & 1) + mips_cpu.options |= MIPS_CPU_FPU; + mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; + break; + case PRID_IMP_5KC: + mips_cpu.cputype = CPU_5KC; + mips_cpu.cputype = MIPS_CPU_ISA_M64; + /* See comment above about querying options */ + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | + MIPS_CPU_DIVEC | MIPS_CPU_WATCH; + config1 = read_mips32_cp0_config1(); + if (config1 & (1 << 3)) + mips_cpu.options |= MIPS_CPU_WATCH; + if (config1 & (1 << 2)) + mips_cpu.options |= MIPS_CPU_MIPS16; + if (config1 & 1) + mips_cpu.options |= MIPS_CPU_FPU; + break; + mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; + default: + mips_cpu.cputype = CPU_UNKNOWN; + break; + } break; +#endif + case PRID_COMP_ALCHEMY: + switch (mips_cpu.processor_id & 0xff00) { #ifdef CONFIG_CPU_MIPS32 - case PRID_IMP_4KC: - mips_cpu.cputype = CPU_4KC; - mips_cpu.isa_level = MIPS_CPU_ISA_M32; - mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | - MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | - MIPS_CPU_DIVEC | MIPS_CPU_WATCH; - config1 = read_mips32_cp0_config1(); - if (config1 & (1 << 3)) - mips_cpu.options |= MIPS_CPU_WATCH; - if (config1 & (1 << 2)) - mips_cpu.options |= MIPS_CPU_MIPS16; - if (config1 & 1) - mips_cpu.options |= MIPS_CPU_FPU; - mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; + case PRID_IMP_AU1000: + mips_cpu.cputype = CPU_AU1000; + mips_cpu.isa_level = MIPS_CPU_ISA_M32; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | + MIPS_CPU_DIVEC | MIPS_CPU_WATCH; + config1 = read_mips32_cp0_config1(); + if (config1 & (1 << 3)) + mips_cpu.options |= MIPS_CPU_WATCH; + if (config1 & (1 << 2)) + mips_cpu.options |= MIPS_CPU_MIPS16; + if (config1 & 1) + mips_cpu.options |= MIPS_CPU_FPU; + mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; + break; +#endif + default: + mips_cpu.cputype = CPU_UNKNOWN; + break; + } break; - case PRID_IMP_5KC: - mips_cpu.cputype = CPU_5KC; - mips_cpu.isa_level = MIPS_CPU_ISA_M64; - mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | - MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | - MIPS_CPU_DIVEC | MIPS_CPU_WATCH; - config1 = read_mips32_cp0_config1(); - if (config1 & (1 << 3)) - mips_cpu.options |= MIPS_CPU_WATCH; - if (config1 & (1 << 2)) - mips_cpu.options |= MIPS_CPU_MIPS16; - if (config1 & 1) - mips_cpu.options |= MIPS_CPU_FPU; - mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; + case PRID_COMP_SIBYTE: + switch (mips_cpu.processor_id & 0xff00) { + case PRID_IMP_SB1: + mips_cpu.cputype = CPU_SB1; + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | + MIPS_CPU_COUNTER | MIPS_CPU_DIVEC | MIPS_CPU_FPU | + MIPS_CPU_VCE; + break; + default: + mips_cpu.cputype = CPU_UNKNOWN; + break; + } break; -#endif default: mips_cpu.cputype = CPU_UNKNOWN; } @@ -329,9 +396,6 @@ init_arch(int argc, char **argv, char **envp, int *prom_vec) #ifdef CONFIG_SGI_IP22 sgi_sysinit(); #endif -#ifdef CONFIG_COBALT_MICRO_SERVER - SetUpBootInfo(); -#endif /* * Determine the mmu/cache attached to this machine, @@ -349,25 +413,116 @@ init_arch(int argc, char **argv, char **envp, int *prom_vec) start_kernel(); } -static void __init default_irq_setup(void) +void __init add_memory_region(unsigned long start, unsigned long size, + long type) { - panic("Unknown machtype in init_IRQ"); + int x = boot_mem_map.nr_map; + + if (x == BOOT_MEM_MAP_MAX) { + printk("Ooops! Too many entries in the memory map!\n"); + return; + } + + boot_mem_map.map[x].addr = start; + boot_mem_map.map[x].size = size; + boot_mem_map.map[x].type = type; + boot_mem_map.nr_map++; +} + +static void __init print_memory_map(void) +{ + int i; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + printk(" memory: %08lx @ %08lx ", + boot_mem_map.map[i].size, boot_mem_map.map[i].addr); + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RAM: + printk("(usable)\n"); + break; + case BOOT_MEM_ROM_DATA: + printk("(ROM data)\n"); + break; + case BOOT_MEM_RESERVED: + printk("(reserved)\n"); + break; + default: + printk("type %lu\n", boot_mem_map.map[i].type); + break; + } + } +} + +static inline void parse_mem_cmdline(void) +{ + char c = ' ', *to = command_line, *from = saved_command_line; + unsigned long start_at, mem_size; + int len = 0; + int usermem = 0; + + printk("Determined physical RAM map:\n"); + print_memory_map(); + + for (;;) { + /* + * "mem=XXX[kKmM]" defines a memory region from + * 0 to <XXX>, overriding the determined size. + * "mem=XXX[KkmM]@YYY[KkmM]" defines a memory region from + * <YYY> to <YYY>+<XXX>, overriding the determined size. + */ + if (c == ' ' && !memcmp(from, "mem=", 4)) { + if (to != command_line) + to--; + /* + * If a user specifies memory size, we + * blow away any automatically generated + * size. + */ + if (usermem == 0) { + boot_mem_map.nr_map = 0; + usermem = 1; + } + mem_size = memparse(from + 4, &from); + if (*from == '@') + start_at = memparse(from + 1, &from); + else + start_at = 0; + add_memory_region(start_at, mem_size, BOOT_MEM_RAM); + } + c = *(from++); + if (!c) + break; + if (COMMAND_LINE_SIZE <= ++len) + break; + *(to++) = c; + } + *to = '\0'; + + if (usermem) { + printk("User-defined physical RAM map:\n"); + print_memory_map(); + } } void __init setup_arch(char **cmdline_p) { + void atlas_setup(void); void baget_setup(void); - void cobalt_setup(void); + void ddb_setup(void); void decstation_setup(void); void deskstation_setup(void); void jazz_setup(void); void sni_rm200_pci_setup(void); void sgi_setup(void); - void ddb_setup(void); - void orion_setup(void); + void ev96100_setup(void); + void malta_setup(void); + void momenco_ocelot_setup(void); + void nino_setup(void); + + unsigned long bootmap_size; + unsigned long start_pfn, max_pfn, first_usable_pfn; - /* Save defaults for configuration-dependent routines. */ - irq_setup = default_irq_setup; + int i; #ifdef CONFIG_BLK_DEV_FD fd_ops = &no_fd_ops; @@ -390,21 +545,31 @@ void __init setup_arch(char **cmdline_p) baget_setup(); break; #endif -#ifdef CONFIG_COBALT_MICRO_SERVER - case MACH_GROUP_COBALT: - cobalt_setup(); - break; -#endif #ifdef CONFIG_DECSTATION case MACH_GROUP_DEC: decstation_setup(); break; #endif +#ifdef CONFIG_MIPS_ATLAS + case MACH_GROUP_UNKNOWN: + atlas_setup(); + break; +#endif #ifdef CONFIG_MIPS_JAZZ case MACH_GROUP_JAZZ: jazz_setup(); break; #endif +#ifdef CONFIG_MIPS_MALTA + case MACH_GROUP_UNKNOWN: + malta_setup(); + break; +#endif +#ifdef CONFIG_MOMENCO_OCELOT + case MACH_GROUP_MOMENCO: + momenco_ocelot_setup(); + break; +#endif #ifdef CONFIG_SGI_IP22 /* As of now this is only IP22. */ case MACH_GROUP_SGI: @@ -421,42 +586,193 @@ void __init setup_arch(char **cmdline_p) ddb_setup(); break; #endif -#ifdef CONFIG_ORION - case MACH_GROUP_ORION: - orion_setup(); +#ifdef CONFIG_DDB5476 + case MACH_GROUP_NEC_DDB: + ddb_setup(); + break; +#endif +#ifdef CONFIG_DDB5477 + case MACH_GROUP_NEC_DDB: + ddb_setup(); + break; +#endif +#ifdef CONFIG_MIPS_EV96100 + case MACH_GROUP_GALILEO: + ev96100_setup(); + break; +#endif +#ifdef CONFIG_MIPS_EV64120 + case MACH_GROUP_GALILEO: + ev64120_setup(); + break; +#endif +#if defined(CONFIG_MIPS_IVR) || defined(CONFIG_MIPS_ITE8172) + case MACH_GROUP_ITE: + case MACH_GROUP_GLOBESPAN: + it8172_setup(); + break; +#endif +#ifdef CONFIG_NINO + case MACH_GROUP_PHILIPS: + nino_setup(); + break; +#endif +#ifdef CONFIG_MIPS_PB1000 + case MACH_GROUP_ALCHEMY: + au1000_setup(); break; #endif default: panic("Unsupported architecture"); } - strncpy (command_line, arcs_cmdline, CL_SIZE); - memcpy(saved_command_line, command_line, CL_SIZE); - saved_command_line[CL_SIZE-1] = '\0'; - + strncpy(command_line, arcs_cmdline, sizeof command_line); + command_line[sizeof command_line - 1] = 0; + strcpy(saved_command_line, command_line); *cmdline_p = command_line; + parse_mem_cmdline(); + +#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) + + /* + * Partially used pages are not usable - thus + * we are rounding upwards. + */ + start_pfn = PFN_UP(__pa(&_end)); + + /* Find the highest page frame number we have available. */ + max_pfn = 0; + first_usable_pfn = -1UL; + for (i = 0; i < boot_mem_map.nr_map; i++) { + unsigned long start, end; + + if (boot_mem_map.map[i].type != BOOT_MEM_RAM) + continue; + + start = PFN_UP(boot_mem_map.map[i].addr); + end = PFN_DOWN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + + if (start >= end) + continue; + if (end > max_pfn) + max_pfn = end; + if (start < first_usable_pfn) { + if (start > start_pfn) { + first_usable_pfn = start; + } else if (end > start_pfn) { + first_usable_pfn = start_pfn; + } + } + } + + /* Initialize the boot-time allocator. */ + bootmap_size = init_bootmem(first_usable_pfn, max_pfn); + + /* + * Register fully available low RAM pages with the bootmem allocator. + */ + for (i = 0; i < boot_mem_map.nr_map; i++) { + unsigned long curr_pfn, last_pfn, size; + + /* + * Reserve usable memory. + */ + if (boot_mem_map.map[i].type != BOOT_MEM_RAM) + continue; + + /* + * We are rounding up the start address of usable memory: + */ + curr_pfn = PFN_UP(boot_mem_map.map[i].addr); + if (curr_pfn >= max_pfn) + continue; + if (curr_pfn < start_pfn) + curr_pfn = start_pfn; + + /* + * ... and at the end of the usable range downwards: + */ + last_pfn = PFN_DOWN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + + if (last_pfn > max_pfn) + last_pfn = max_pfn; + + /* + * ... finally, did all the rounding and playing + * around just make the area go away? + */ + if (last_pfn <= curr_pfn) + continue; + + size = last_pfn - curr_pfn; + free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); + } + + /* Reserve the bootmap memory. */ + reserve_bootmem(PFN_PHYS(first_usable_pfn), bootmap_size); + #ifdef CONFIG_BLK_DEV_INITRD -#error "Fixme, I'm broken." - tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8; - if (tmp < (unsigned long)&_end) - tmp += PAGE_SIZE; - initrd_header = (unsigned long *)tmp; - if (initrd_header[0] == 0x494E5244) { - initrd_start = (unsigned long)&initrd_header[2]; - initrd_end = initrd_start + initrd_header[1]; - initrd_below_start_ok = 1; - if (initrd_end > memory_end) { + /* Board specific code should have set up initrd_start and initrd_end */ + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + initrd_start = (unsigned long)&__rd_start; + initrd_end = (unsigned long)&__rd_end; + initrd_below_start_ok = 1; + if (initrd_start) { + unsigned long initrd_size = ((unsigned char *)initrd_end) - ((unsigned char *)initrd_start); + printk("Initial ramdisk at: 0x%p (%lu bytes)\n", + (void *)initrd_start, + initrd_size); + if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) { printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_end,memory_end); - initrd_start = 0; - } else - *memory_start_p = initrd_end; + "(0x%lx > 0x%p)\ndisabling initrd\n", + initrd_end, + phys_to_virt(PFN_PHYS(max_low_pfn))); + initrd_start = initrd_end = 0; + } } -#endif +#endif /* CONFIG_BLK_DEV_INITRD */ paging_init(); + + code_resource.start = virt_to_bus(&_ftext); + code_resource.end = virt_to_bus(&_etext) - 1; + data_resource.start = virt_to_bus(&_fdata); + data_resource.end = virt_to_bus(&_edata) - 1; + + /* + * Request address space for all standard RAM. + */ + for (i = 0; i < boot_mem_map.nr_map; i++) { + struct resource *res; + + res = alloc_bootmem(sizeof(struct resource)); + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RAM: + case BOOT_MEM_ROM_DATA: + res->name = "System RAM"; + break; + case BOOT_MEM_RESERVED: + default: + res->name = "reserved"; + } + res->start = boot_mem_map.map[i].addr; + res->end = res->start + boot_mem_map.map[i].size - 1; + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + request_resource(&iomem_resource, res); + + /* + * We dont't know which RAM region contains kernel data, + * so we try it repeatedly and let the resource manager + * test it. + */ + request_resource(res, &code_resource); + request_resource(res, &data_resource); + } } void r3081_wait(void) diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c new file mode 100644 index 000000000000..41404069877a --- /dev/null +++ b/arch/mips/kernel/smp.c @@ -0,0 +1,402 @@ +/* + * + * arch/mips/kernel/smp.c + * + * Copyright (C) 2000 Sibyte + * + * Written by Justin Carlson (carlson@sibyte.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/threads.h> +#include <linux/time.h> +#include <linux/timex.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include <asm/atomic.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/hardirq.h> +#include <asm/softirq.h> +#include <asm/mmu_context.h> +#include <asm/delay.h> +#include <asm/smp.h> + +/* + * This was written with the BRCM12500 MP SOC in mind, but tries to + * be generic. It's modelled on the mips64 smp.c code, which is + * derived from Sparc, I'm guessing, which is derived from... + * + * It's probably horribly designed for very large ccNUMA systems + * as it doesn't take any node clustering into account. +*/ + + +/* Ze Big Kernel Lock! */ +spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +int smp_threads_ready; /* Not used */ +int smp_num_cpus; +int global_irq_holder = NO_PROC_ID; +spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; +struct mips_cpuinfo cpu_data[NR_CPUS]; + +struct smp_fn_call_struct smp_fn_call = +{ SPIN_LOCK_UNLOCKED, ATOMIC_INIT(0), NULL, NULL}; + +static atomic_t cpus_booted = ATOMIC_INIT(0); + + +/* These are defined by the board-specific code. */ + +/* Cause the function described by smp_fn_call + to be executed on the passed cpu. When the function + has finished, increment the finished field of + smp_fn_call. */ + +void core_call_function(int cpu); + +/* + * Clear all undefined state in the cpu, set up sp and gp to the passed + * values, and kick the cpu into smp_bootstrap(); + */ +void prom_boot_secondary(int cpu, unsigned long sp, unsigned long gp); + +/* + * After we've done initial boot, this function is called to allow the + * board code to clean up state, if needed + */ + +void prom_init_secondary(void); + + +void cpu_idle(void); + +/* Do whatever setup needs to be done for SMP at the board level. Return + the number of cpus in the system, including this one */ +int prom_setup_smp(void); + +int start_secondary(void *unused) +{ + prom_init_secondary(); + write_32bit_cp0_register(CP0_CONTEXT, smp_processor_id()<<23); + current_pgd[smp_processor_id()] = init_mm.pgd; + printk("Slave cpu booted successfully\n"); + atomic_inc(&cpus_booted); + cpu_idle(); + return 0; +} + +void __init smp_boot_cpus(void) +{ + int i; + + smp_num_cpus = prom_setup_smp(); + init_new_context(current, &init_mm); + current->processor = 0; + atomic_set(&cpus_booted, 1); /* Master CPU is already booted... */ + init_idle(); + for (i = 1; i < smp_num_cpus; i++) { + struct task_struct *p; + struct pt_regs regs; + printk("Starting CPU %d... ", i); + + /* Spawn a new process normally. Grab a pointer to + its task struct so we can mess with it */ + do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); + p = init_task.prev_task; + + /* Schedule the first task manually */ + p->processor = i; + p->has_cpu = 1; + + /* Attach to the address space of init_task. */ + atomic_inc(&init_mm.mm_count); + p->active_mm = &init_mm; + init_tasks[i] = p; + + del_from_runqueue(p); + unhash_process(p); + + prom_boot_secondary(i, + (unsigned long)p + KERNEL_STACK_SIZE - 32, + (unsigned long)p); + +#if 0 + + /* This is copied from the ip-27 code in the mips64 tree */ + + struct task_struct *p; + + /* + * The following code is purely to make sure + * Linux can schedule processes on this slave. + */ + kernel_thread(0, NULL, CLONE_PID); + p = init_task.prev_task; + sprintf(p->comm, "%s%d", "Idle", i); + init_tasks[i] = p; + p->processor = i; + p->has_cpu = 1; /* we schedule the first task manually */ + del_from_runqueue(p); + unhash_process(p); + /* Attach to the address space of init_task. */ + atomic_inc(&init_mm.mm_count); + p->active_mm = &init_mm; + prom_boot_secondary(i, + (unsigned long)p + KERNEL_STACK_SIZE - 32, + (unsigned long)p); +#endif + } + + /* Wait for everyone to come up */ + while (atomic_read(&cpus_booted) != smp_num_cpus); +} + +void __init smp_commence(void) +{ + /* Not sure what to do here yet */ +} + +static void reschedule_this_cpu(void *dummy) +{ + current->need_resched = 1; +} + +void FASTCALL(smp_send_reschedule(int cpu)) +{ + smp_call_function(reschedule_this_cpu, NULL, 0, 0); +} + + +/* + * The caller of this wants the passed function to run on every cpu. If wait + * is set, wait until all cpus have finished the function before returning. + * The lock is here to protect the call structure. + */ +int smp_call_function (void (*func) (void *info), void *info, int retry, + int wait) +{ + int cpus = smp_num_cpus - 1; + int i; + + if (smp_num_cpus < 2) { + return 0; + } + + spin_lock_bh(&smp_fn_call.lock); + + atomic_set(&smp_fn_call.finished, 0); + smp_fn_call.fn = func; + smp_fn_call.data = info; + + for (i = 0; i < smp_num_cpus; i++) { + if (i != smp_processor_id()) { + /* Call the board specific routine */ + core_call_function(i); + } + } + + if (wait) { + while(atomic_read(&smp_fn_call.finished) != cpus) {} + } + + spin_unlock_bh(&smp_fn_call.lock); + return 0; +} + +void synchronize_irq(void) +{ + panic("synchronize_irq"); +} + +static void stop_this_cpu(void *dummy) +{ + printk("Cpu stopping\n"); + for (;;); +} + +void smp_send_stop(void) +{ + smp_call_function(stop_this_cpu, NULL, 1, 0); + smp_num_cpus = 1; +} + +/* Not really SMP stuff ... */ +int setup_profiling_timer(unsigned int multiplier) +{ + return 0; +} + + +/* + * Most of this code is take from the mips64 tree (ip27-irq.c). It's virtually + * identical to the i386 implentation in arh/i386/irq.c, with translations for + * the interrupt enable bit + */ + +#define MAXCOUNT 100000000 +#define SYNC_OTHER_CORES(x) udelay(x+1) + +static inline void wait_on_irq(int cpu) +{ + int count = MAXCOUNT; + + for (;;) { + + /* + * Wait until all interrupts are gone. Wait + * for bottom half handlers unless we're + * already executing in one.. + */ + if (!irqs_running()) + if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock)) + break; + + /* Duh, we have to loop. Release the lock to avoid deadlocks */ + spin_unlock(&global_irq_lock); + + for (;;) { + if (!--count) { + printk("Count spun out. Huh?\n"); + count = ~0; + } + __sti(); + SYNC_OTHER_CORES(cpu); + __cli(); + if (irqs_running()) + continue; + if (spin_is_locked(&global_irq_lock)) + continue; + if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock)) + continue; + if (spin_trylock(&global_irq_lock)) + break; + } + } +} + + +static inline void get_irqlock(int cpu) +{ + if (!spin_trylock(&global_irq_lock)) { + /* do we already hold the lock? */ + if ((unsigned char) cpu == global_irq_holder) + return; + /* Uhhuh.. Somebody else got it. Wait.. */ + spin_lock(&global_irq_lock); + } + /* + * We also to make sure that nobody else is running + * in an interrupt context. + */ + wait_on_irq(cpu); + + /* + * Ok, finally.. + */ + global_irq_holder = cpu; +} + + +/* + * A global "cli()" while in an interrupt context + * turns into just a local cli(). Interrupts + * should use spinlocks for the (very unlikely) + * case that they ever want to protect against + * each other. + * + * If we already have local interrupts disabled, + * this will not turn a local disable into a + * global one (problems with spinlocks: this makes + * save_flags+cli+sti usable inside a spinlock). + */ +void __global_cli(void) +{ + unsigned int flags; + + __save_flags(flags); + if (flags & ST0_IE) { + int cpu = smp_processor_id(); + __cli(); + if (!local_irq_count(cpu)) + get_irqlock(cpu); + } +} + +void __global_sti(void) +{ + int cpu = smp_processor_id(); + + if (!local_irq_count(cpu)) + release_irqlock(cpu); + __sti(); +} + +/* + * SMP flags value to restore to: + * 0 - global cli + * 1 - global sti + * 2 - local cli + * 3 - local sti + */ +unsigned long __global_save_flags(void) +{ + int retval; + int local_enabled; + unsigned long flags; + int cpu = smp_processor_id(); + + __save_flags(flags); + local_enabled = (flags & ST0_IE); + /* default to local */ + retval = 2 + local_enabled; + + /* check for global flags if we're not in an interrupt */ + if (!local_irq_count(cpu)) { + if (local_enabled) + retval = 1; + if (global_irq_holder == cpu) + retval = 0; + } + + return retval; +} + +void __global_restore_flags(unsigned long flags) +{ + switch (flags) { + case 0: + __global_cli(); + break; + case 1: + __global_sti(); + break; + case 2: + __cli(); + break; + case 3: + __sti(); + break; + default: + printk("global_restore_flags: %08lx\n", flags); + } +} diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 741f1a9e88c0..0a8f79664e30 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -92,22 +92,23 @@ sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, return do_mmap2(addr, len, prot, flags, fd, pgoff); } -asmlinkage int sys_fork(struct pt_regs regs) +save_static_function(sys_fork); +static_unused int _sys_fork(struct pt_regs regs) { int res; - save_static(®s); res = do_fork(SIGCHLD, regs.regs[29], ®s, 0); return res; } -asmlinkage int sys_clone(struct pt_regs regs) + +save_static_function(sys_clone); +static_unused int _sys_clone(struct pt_regs regs) { unsigned long clone_flags; unsigned long newsp; int res; - save_static(®s); clone_flags = regs.regs[4]; newsp = regs.regs[5]; if (!newsp) diff --git a/arch/mips/kernel/syscalls.h b/arch/mips/kernel/syscalls.h index 4a8088b8afbf..9a6795f4e8f3 100644 --- a/arch/mips/kernel/syscalls.h +++ b/arch/mips/kernel/syscalls.h @@ -1,10 +1,9 @@ -/* $Id: syscalls.h,v 1.22 2000/02/18 00:24:30 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle + * Copyright (C) 1995, 96, 97, 98, 99, 2000 by Ralf Baechle */ /* @@ -228,10 +227,11 @@ SYS(sys_ni_syscall, 0) SYS(sys_mmap2, 6) /* 4210 */ SYS(sys_truncate64, 2) SYS(sys_ftruncate64, 2) -SYS(sys_stat64, 3) -SYS(sys_lstat64, 3) -SYS(sys_fstat64, 3) /* 4215 */ +SYS(sys_stat64, 2) +SYS(sys_lstat64, 2) +SYS(sys_fstat64, 2) /* 4215 */ SYS(sys_pivot_root, 2) SYS(sys_mincore, 3) SYS(sys_madvise, 3) SYS(sys_getdents64, 3) +SYS(sys_fcntl64, 3) /* 4220 */ diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index c87a36fb050e..18ec04e236e4 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -3,7 +3,7 @@ * * Copyright (C) 1996 David S. Miller * Copyright (C) 1997 Miguel de Icaza - * Copyright (C) 1997, 1998 Ralf Baechle + * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle */ #include <linux/kernel.h> #include <linux/sched.h> @@ -27,7 +27,6 @@ #include <asm/page.h> #include <asm/pgalloc.h> #include <asm/uaccess.h> -#include <asm/sgialib.h> #include <asm/inventory.h> /* 2,191 lines of complete and utter shit coming up... */ @@ -1249,9 +1248,9 @@ static inline void irix_xstat64_xlate(struct stat *sb) ks.st_blksize = (s32) sb->st_blksize; ks.st_blocks = (long long) sb->st_blocks; - memcpy(&ks.st_fstype[0], &sb->st_fstype[0], 16); - ks.st_pad4[0] = ks.st_pad4[1] = ks.st_pad4[2] = ks.st_pad4[3] = - ks.st_pad4[4] = ks.st_pad4[5] = ks.st_pad4[6] = ks.st_pad4[7] = 0; + memset(ks.st_fstype, 0, 16); + ks.st_pad4[0] = ks.st_pad4[1] = ks.st_pad4[2] = ks.st_pad4[3] = 0; + ks.st_pad4[4] = ks.st_pad4[5] = ks.st_pad4[6] = ks.st_pad4[7] = 0; /* Now write it all back. */ copy_to_user(sb, &ks, sizeof(struct xstat64)); diff --git a/arch/mips/kernel/sysmips.c b/arch/mips/kernel/sysmips.c index 7d34f2d8cce5..ab028258a82a 100644 --- a/arch/mips/kernel/sysmips.c +++ b/arch/mips/kernel/sysmips.c @@ -7,6 +7,7 @@ * * Copyright (C) 1995, 1996, 1997, 2000 by Ralf Baechle */ +#include <linux/config.h> #include <linux/errno.h> #include <linux/linkage.h> #include <linux/mm.h> @@ -21,6 +22,8 @@ #include <asm/sysmips.h> #include <asm/uaccess.h> +extern asmlinkage void syscall_trace(void); + /* * How long a hostname can we get from user space? * -EFAULT if invalid area or too long @@ -49,7 +52,7 @@ sys_sysmips(int cmd, int arg1, int arg2, int arg3) { int *p; char *name; - int flags, tmp, len, retval, errno; + int tmp, len, retval, errno; switch(cmd) { case SETNAME: { @@ -72,8 +75,7 @@ sys_sysmips(int cmd, int arg1, int arg2, int arg3) } case MIPS_ATOMIC_SET: { - /* This is broken in case of page faults and SMP ... - Risc/OS faults after maximum 20 tries with EAGAIN. */ +#ifdef CONFIG_CPU_HAS_LLSC unsigned int tmp; p = (int *) arg1; @@ -81,16 +83,46 @@ sys_sysmips(int cmd, int arg1, int arg2, int arg3) if (errno) return errno; errno = 0; - save_and_cli(flags); - errno |= __get_user(tmp, p); - errno |= __put_user(arg2, p); - restore_flags(flags); + + __asm__(".set\tpush\t\t\t# sysmips(MIPS_ATOMIC, ...)\n\t" + ".set\tmips2\n\t" + ".set\tnoat\n\t" + "1:\tll\t%0, %4\n\t" + "move\t$1, %3\n\t" + "2:\tsc\t$1, %1\n\t" + "beqz\t$1, 1b\n\t" + ".set\tpop\n\t" + ".section\t.fixup,\"ax\"\n" + "3:\tli\t%2, 1\t\t\t# error\n\t" + ".previous\n\t" + ".section\t__ex_table,\"a\"\n\t" + ".word\t1b, 3b\n\t" + ".word\t2b, 3b\n\t" + ".previous\n\t" + : "=&r" (tmp), "=o" (* (u32 *) p), "=r" (errno) + : "r" (arg2), "o" (* (u32 *) p), "2" (errno) + : "$1"); if (errno) - return tmp; + return -EFAULT; - return tmp; /* This is broken ... */ - } + /* We're skipping error handling etc. */ + if (current->ptrace & PT_TRACESYS) + syscall_trace(); + + ((struct pt_regs *)&cmd)->regs[2] = tmp; + ((struct pt_regs *)&cmd)->regs[7] = 0; + + __asm__ __volatile__( + "move\t$29, %0\n\t" + "j\to32_ret_from_sys_call" + : /* No outputs */ + : "r" (&cmd)); + /* Unreached */ +#else + printk("sys_sysmips(MIPS_ATOMIC_SET, ...) not ready for !CONFIG_CPU_HAS_LLSC\n"); +#endif + } case MIPS_FIXADE: tmp = current->thread.mflags & ~3; diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index af4af4fc3929..2d05f03c27f1 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -1,551 +1,542 @@ -/* - * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * Copyright (C) 1996 - 2000 Ralf Baechle +/*********************************************************************** + * Copyright 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * arch/mips/kernel/time.c + * Common time service routines for MIPS machines. See + * Documents/MIPS/time.txt. * - * This file contains the time handling details for PC-style clocks as - * found in some MIPS systems. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + *********************************************************************** */ + #include <linux/config.h> -#include <linux/errno.h> +#include <linux/types.h> +#include <linux/kernel.h> #include <linux/init.h> #include <linux/sched.h> -#include <linux/kernel.h> #include <linux/param.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/interrupt.h> +#include <linux/time.h> +#include <linux/smp.h> #include <linux/kernel_stat.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> #include <asm/bootinfo.h> -#include <asm/mipsregs.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/ddb5074.h> +#include <asm/cpu.h> +#include <asm/time.h> +#include <asm/hardirq.h> + +/* + * macro for catching spurious errors. Eable to LL_DEBUG in kernel hacking + * config menu. + */ +#ifdef CONFIG_LL_DEBUG +#define MIPS_ASSERT(x) if (!(x)) { panic("MIPS_ASSERT failed at %s:%d\n", __FILE__, __LINE__); } +#define MIPS_DEBUG(x) do { x; } while (0) +#else +#define MIPS_ASSERT(x) +#define MIPS_DEBUG(x) +#endif -#include <linux/mc146818rtc.h> -#include <linux/timex.h> +/* This is for machines which generate the exact clock. */ +#define USECS_PER_JIFFY (1000000/HZ) +#define USECS_PER_JIFFY_FRAC (0x100000000*1000000/HZ&0xffffffff) -extern volatile unsigned long wall_jiffies; -unsigned long r4k_interval; +/* + * forward reference + */ extern rwlock_t xtime_lock; +extern volatile unsigned long wall_jiffies; /* - * Change this if you have some constant time drift + * By default we provide the null RTC ops */ -/* This is the value for the PC-style PICs. */ -/* #define USECS_PER_JIFFY (1000020/HZ) */ +static unsigned long null_rtc_get_time(void) +{ + return mktime(2000, 1, 1, 0, 0, 0); +} -/* This is for machines which generate the exact clock. */ -#define USECS_PER_JIFFY (1000000/HZ) +static int null_rtc_set_time(unsigned long sec) +{ + return 0; +} -/* Cycle counter value at the previous timer interrupt.. */ +unsigned long (*rtc_get_time)(void) = null_rtc_get_time; +int (*rtc_set_time)(unsigned long) = null_rtc_set_time; -static unsigned int timerhi, timerlo; /* - * On MIPS only R4000 and better have a cycle counter. - * - * FIXME: Does playing with the RP bit in c0_status interfere with this code? + * timeofday services, for syscalls. */ -static unsigned long do_fast_gettimeoffset(void) +void do_gettimeofday(struct timeval *tv) { - u32 count; - unsigned long res, tmp; - - /* Last jiffy when do_fast_gettimeoffset() was called. */ - static unsigned long last_jiffies; - unsigned long quotient; - - /* - * Cached "1/(clocks per usec)*2^32" value. - * It has to be recalculated once each jiffy. - */ - static unsigned long cached_quotient; - - tmp = jiffies; - - quotient = cached_quotient; - - if (tmp && last_jiffies != tmp) { - last_jiffies = tmp; - __asm__(".set\tnoreorder\n\t" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "lwu\t%0,%2\n\t" - "dsll32\t$1,%1,0\n\t" - "or\t$1,$1,%0\n\t" - "ddivu\t$0,$1,%3\n\t" - "mflo\t$1\n\t" - "dsll32\t%0,%4,0\n\t" - "nop\n\t" - "ddivu\t$0,%0,$1\n\t" - "mflo\t%0\n\t" - ".set\tmips0\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=&r" (quotient) - :"r" (timerhi), - "m" (timerlo), - "r" (tmp), - "r" (USECS_PER_JIFFY) - :"$1"); - cached_quotient = quotient; - } + unsigned long flags; - /* Get last timer tick in absolute kernel time */ - count = read_32bit_cp0_register(CP0_COUNT); + read_lock_irqsave (&xtime_lock, flags); + *tv = xtime; + tv->tv_usec += do_gettimeoffset(); - /* .. relative to previous jiffy (32 bits is enough) */ - count -= timerlo; -//printk("count: %08lx, %08lx:%08lx\n", count, timerhi, timerlo); + /* + * xtime is atomically updated in timer_bh. jiffies - wall_jiffies + * is nonzero if the timer bottom half hasnt executed yet. + */ + if (jiffies - wall_jiffies) + tv->tv_usec += USECS_PER_JIFFY; - __asm__("multu\t%1,%2\n\t" - "mfhi\t%0" - :"=r" (res) - :"r" (count), - "r" (quotient)); + read_unlock_irqrestore (&xtime_lock, flags); - /* - * Due to possible jiffies inconsistencies, we need to check - * the result so that we'll get a timer that is monotonic. - */ - if (res >= USECS_PER_JIFFY) - res = USECS_PER_JIFFY-1; + if (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } +} - return res; +void do_settimeofday(struct timeval *tv) +{ + write_lock_irq (&xtime_lock); + + /* This is revolting. We need to set the xtime.tv_usec + * correctly. However, the value in this location is + * is value at the last tick. + * Discover what correction gettimeofday + * would have done, and then undo it! + */ + tv->tv_usec -= do_gettimeoffset(); + + if (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + xtime = *tv; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + + write_unlock_irq (&xtime_lock); } -/* This function must be called with interrupts disabled - * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs - * - * However, the pc-audio speaker driver changes the divisor so that - * it gets interrupted rather more often - it loads 64 into the - * counter rather than 11932! This has an adverse impact on - * do_gettimeoffset() -- it stops working! What is also not - * good is that the interval that our timer function gets called - * is no longer 10.0002 ms, but 9.9767 ms. To get around this - * would require using a different timing source. Maybe someone - * could use the RTC - I know that this can interrupt at frequencies - * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix - * it so that at startup, the timer code in sched.c would select - * using either the RTC or the 8253 timer. The decision would be - * based on whether there was any other device around that needed - * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz, - * and then do some jiggery to have a version of do_timer that - * advanced the clock by 1/1024 s. Every time that reached over 1/100 - * of a second, then do all the old code. If the time was kept correct - * then do_gettimeoffset could just return 0 - there is no low order - * divider that can be accessed. + +/* + * Gettimeoffset routines. These routines returns the time duration + * since last timer interrupt in usecs. * - * Ideally, you would be able to use the RTC for the speaker driver, - * but it appears that the speaker driver really needs interrupt more - * often than every 120 us or so. + * If the exact CPU counter frequency is known, use fixed_rate_gettimeoffset. + * Otherwise use calibrate_gettimeoffset() * - * Anyway, this needs more thought.... pjsg (1993-08-28) - * - * If you are really that interested, you should be reading - * comp.protocols.time.ntp! + * If the CPU does not have counter register all, you can either supply + * your own gettimeoffset() routine, or use null_gettimeoffset() routines, + * which gives the same resolution as HZ. */ -#define TICK_SIZE tick -static unsigned long do_slow_gettimeoffset(void) -{ - int count; +/* This is for machines which generate the exact clock. */ +#define USECS_PER_JIFFY (1000000/HZ) - static int count_p = LATCH; /* for the first call after boot */ - static unsigned long jiffies_p; +/* usecs per counter cycle, shifted to left by 32 bits */ +static unsigned int sll32_usecs_per_cycle=0; - /* - * cache volatile jiffies temporarily; we have IRQs turned off. - */ - unsigned long jiffies_t; +/* how many counter cycles in a jiffy */ +static unsigned long cycles_per_jiffy=0; + +/* Cycle counter value at the previous timer interrupt.. */ +static unsigned int timerhi, timerlo; - /* timer count may underflow right here */ - outb_p(0x00, 0x43); /* latch the count ASAP */ +/* last time when xtime and rtc are sync'ed up */ +static long last_rtc_update; - count = inb_p(0x40); /* read the latched count */ +/* the function pointer to one of the gettimeoffset funcs*/ +unsigned long (*do_gettimeoffset)(void) = null_gettimeoffset; - /* - * We do this guaranteed double memory access instead of a _p - * postfix in the previous port access. Wheee, hackady hack - */ - jiffies_t = jiffies; +unsigned long null_gettimeoffset(void) +{ + return 0; +} - count |= inb_p(0x40) << 8; +unsigned long fixed_rate_gettimeoffset(void) +{ + u32 count; + unsigned long res; - /* - * avoiding timer inconsistencies (they are rare, but they happen)... - * there are two kinds of problems that must be avoided here: - * 1. the timer counter underflows - * 2. hardware problem with the timer, not giving us continuous time, - * the counter does small "jumps" upwards on some Pentium systems, - * (see c't 95/10 page 335 for Neptun bug.) - */ + MIPS_ASSERT(mips_cpu.options & MIPS_CPU_COUNTER); + MIPS_ASSERT(mips_counter_frequency != 0); + MIPS_ASSERT(sll32_usecs_per_cycle != 0); - if( jiffies_t == jiffies_p ) { - if( count > count_p ) { - /* the nutcase */ - - outb_p(0x0A, 0x20); - - /* assumption about timer being IRQ1 */ - if (inb(0x20) & 0x01) { - /* - * We cannot detect lost timer interrupts ... - * well, that's why we call them lost, don't we? :) - * [hmm, on the Pentium and Alpha we can ... sort of] - */ - count -= LATCH; - } else { - printk("do_slow_gettimeoffset(): hardware timer problem?\n"); - } - } - } else - jiffies_p = jiffies_t; + /* Get last timer tick in absolute kernel time */ + count = read_32bit_cp0_register(CP0_COUNT); - count_p = count; + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; - count = ((LATCH-1) - count) * TICK_SIZE; - count = (count + LATCH/2) / LATCH; + __asm__("multu\t%1,%2\n\t" + "mfhi\t%0" + :"=r" (res) + :"r" (count), + "r" (sll32_usecs_per_cycle)); - return count; -} + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY-1; -static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; + return res; +} /* - * This version of gettimeofday has near microsecond resolution. + * Cached "1/(clocks per usec)*2^32" value. + * It has to be recalculated once each jiffy. */ -void do_gettimeofday(struct timeval *tv) -{ - unsigned long flags; +static unsigned long cached_quotient; - read_lock_irqsave (&xtime_lock, flags); - *tv = xtime; - tv->tv_usec += do_gettimeoffset(); +/* Last jiffy when calibrate_divXX_gettimeoffset() was called. */ +static unsigned long last_jiffies = 0; - /* - * xtime is atomically updated in timer_bh. jiffies - wall_jiffies - * is nonzero if the timer bottom half hasnt executed yet. - */ - if (jiffies - wall_jiffies) - tv->tv_usec += USECS_PER_JIFFY; - - read_unlock_irqrestore (&xtime_lock, flags); - - if (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } -} +/* + * copied from include/asm/div64. + * We do the copy instead of include the header file because we don't + * want to reply on _MIPS_ISA value. + */ +#define do_div64_32(res, high, low, base) ({ \ + unsigned long __quot, __mod; \ + unsigned long __cf, __tmp, __i; \ + \ + __asm__(".set push\n\t" \ + ".set noat\n\t" \ + ".set noreorder\n\t" \ + "b 1f\n\t" \ + " li %4,0x21\n" \ + "0:\n\t" \ + "sll $1,%0,0x1\n\t" \ + "srl %3,%0,0x1f\n\t" \ + "or %0,$1,$2\n\t" \ + "sll %1,%1,0x1\n\t" \ + "sll %2,%2,0x1\n" \ + "1:\n\t" \ + "bnez %3,2f\n\t" \ + "sltu $2,%0,%z5\n\t" \ + "bnez $2,3f\n\t" \ + "2:\n\t" \ + " addiu %4,%4,-1\n\t" \ + "subu %0,%0,%z5\n\t" \ + "addiu %2,%2,1\n" \ + "3:\n\t" \ + "bnez %4,0b\n\t" \ + " srl $2,%1,0x1f\n\t" \ + ".set pop" \ + : "=&r" (__mod), "=&r" (__tmp), "=&r" (__quot), "=&r" (__cf), \ + "=&r" (__i) \ + : "Jr" (base), "0" (high), "1" (low), "2" (0), "3" (0) \ + /* Aarrgh! Ran out of gcc's limit on constraints... */ \ + : "$1", "$2"); \ + \ + (res) = __quot; \ + __mod; }) -void do_settimeofday(struct timeval *tv) +/* + * This is copied from dec/time.c:do_ioasic_gettimeoffset() by Mercij. + */ +unsigned long calibrate_div32_gettimeoffset(void) { - write_lock_irq (&xtime_lock); - /* This is revolting. We need to set the xtime.tv_usec - * correctly. However, the value in this location is - * is value at the last tick. - * Discover what correction gettimeofday - * would have done, and then undo it! - */ - tv->tv_usec -= do_gettimeoffset(); + u32 count; + unsigned long res, tmp; + unsigned long quotient; - if (tv->tv_usec < 0) { - tv->tv_usec += 1000000; - tv->tv_sec--; - } + MIPS_ASSERT(mips_cpu.options & MIPS_CPU_COUNTER); - xtime = *tv; - time_adjust = 0; /* stop active adjtime() */ - time_status |= STA_UNSYNC; - time_maxerror = NTP_PHASE_LIMIT; - time_esterror = NTP_PHASE_LIMIT; - write_unlock_irq (&xtime_lock); -} + tmp = jiffies; -/* - * In order to set the CMOS clock precisely, set_rtc_mmss has to be - * called 500 ms after the second nowtime has started, because when - * nowtime is written into the registers of the CMOS clock, it will - * jump to the next second precisely 500 ms later. Check the Motorola - * MC146818A or Dallas DS12887 data sheet for details. - * - * BUG: This routine does not handle hour overflow properly; it just - * sets the minutes. Usually you won't notice until after reboot! - */ -static int set_rtc_mmss(unsigned long nowtime) -{ - int retval = 0; - int real_seconds, real_minutes, cmos_minutes; - unsigned char save_control, save_freq_select; + quotient = cached_quotient; - save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + if (last_jiffies != tmp) { + last_jiffies = tmp; + if (last_jiffies != 0) { + unsigned long r0; + do_div64_32(r0, timerhi, timerlo, tmp); + do_div64_32(quotient, USECS_PER_JIFFY, + USECS_PER_JIFFY_FRAC, r0); + cached_quotient = quotient; + } + } - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + /* Get last timer tick in absolute kernel time */ + count = read_32bit_cp0_register(CP0_COUNT); - cmos_minutes = CMOS_READ(RTC_MINUTES); - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - BCD_TO_BIN(cmos_minutes); + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; - /* - * since we're only adjusting minutes and seconds, - * don't interfere with hour overflow. This avoids - * messing with unknown time zones but requires your - * RTC not to be off by more than 15 minutes - */ - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) - real_minutes += 30; /* correct for half hour time zone */ - real_minutes %= 60; - - if (abs(real_minutes - cmos_minutes) < 30) { - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BIN_TO_BCD(real_seconds); - BIN_TO_BCD(real_minutes); - } - CMOS_WRITE(real_seconds,RTC_SECONDS); - CMOS_WRITE(real_minutes,RTC_MINUTES); - } else { - printk(KERN_WARNING - "set_rtc_mmss: can't update from %d to %d\n", - cmos_minutes, real_minutes); - retval = -1; - } + __asm__("multu %2,%3" + : "=l" (tmp), "=h" (res) + : "r" (count), "r" (quotient)); - /* The following flags have to be released exactly in this order, - * otherwise the DS12887 (popular MC146818A clone with integrated - * battery and quartz) will not reset the oscillator and will not - * update precisely 500 ms later. You won't find this mentioned in - * the Dallas Semiconductor data sheets, but who believes data - * sheets anyway ... -- Markus Kuhn - */ - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY - 1; - return retval; + return res; +} + +unsigned long calibrate_div64_gettimeoffset(void) +{ + u32 count; + unsigned long res, tmp; + unsigned long quotient; + + + MIPS_ASSERT(mips_cpu.options & MIPS_CPU_COUNTER); + MIPS_ASSERT((mips_cpu.isa_level != MIPS_CPU_ISA_I) && + (mips_cpu.isa_level != MIPS_CPU_ISA_II) && + (mips_cpu.isa_level != MIPS_CPU_ISA_M32)); + + + tmp = jiffies; + + quotient = cached_quotient; + + if (tmp && last_jiffies != tmp) { + last_jiffies = tmp; + __asm__(".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "lwu\t%0,%2\n\t" + "dsll32\t$1,%1,0\n\t" + "or\t$1,$1,%0\n\t" + "ddivu\t$0,$1,%3\n\t" + "mflo\t$1\n\t" + "dsll32\t%0,%4,0\n\t" + "nop\n\t" + "ddivu\t$0,%0,$1\n\t" + "mflo\t%0\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=&r" (quotient) + :"r" (timerhi), + "m" (timerlo), + "r" (tmp), + "r" (USECS_PER_JIFFY) + :"$1"); + cached_quotient = quotient; + } + + /* Get last timer tick in absolute kernel time */ + count = read_32bit_cp0_register(CP0_COUNT); + + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; + + __asm__("multu\t%1,%2\n\t" + "mfhi\t%0" + :"=r" (res) + :"r" (count), + "r" (quotient)); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY-1; + + return res; } -/* last time the cmos clock got updated */ -static long last_rtc_update; /* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick + * high-level timer interrupt service routines. This function + * is set as irqaction->handler and is invoked through do_IRQ. */ -static void inline -timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) +void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { -#ifdef CONFIG_DDB5074 - static unsigned cnt, period, dist; + if (mips_cpu.options & MIPS_CPU_COUNTER) { + unsigned int count; + + /* + * The cycle counter is only 32 bit which is good for about + * a minute at current count rates of upto 150MHz or so. + */ + count = read_32bit_cp0_register(CP0_COUNT); + timerhi += (count < timerlo); /* Wrap around */ + timerlo = count; + + /* + * set up for next timer interrupt - no harm if the machine + * is using another timer interrupt source. + * Note that writing to COMPARE register clears the interrupt + */ + write_32bit_cp0_register (CP0_COMPARE, + count + cycles_per_jiffy); - if (cnt == 0 || cnt == dist) - ddb5074_led_d2(1); - else if (cnt == 7 || cnt == dist+7) - ddb5074_led_d2(0); - - if (++cnt > period) { - cnt = 0; - /* The hyperbolic function below modifies the heartbeat period - * length in dependency of the current (5min) load. It goes - * through the points f(0)=126, f(1)=86, f(5)=51, - * f(inf)->30. */ - period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; - dist = period / 4; } -#endif - if(!user_mode(regs)) { + + if(!user_mode(regs)) { if (prof_buffer && current->pid) { - extern int _stext; - unsigned long pc = regs->cp0_epc; - - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - /* - * Dont ignore out-of-bounds pc values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (pc > prof_len-1) - pc = prof_len-1; - atomic_inc((atomic_t *)&prof_buffer[pc]); - } - } - do_timer(regs); + extern int _stext; + unsigned long pc = regs->cp0_epc; + + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + /* + * Dont ignore out-of-bounds pc values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + if (pc > prof_len-1) + pc = prof_len-1; + atomic_inc((atomic_t *)&prof_buffer[pc]); + } + } /* - * If we have an externally synchronized Linux clock, then update - * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be - * called as close as possible to 500 ms before the new second starts. + * call the generic timer interrupt handling */ - read_lock (&xtime_lock); - if ((time_status & STA_UNSYNC) == 0 && - xtime.tv_sec > last_rtc_update + 660 && - xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 && - xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) { - if (set_rtc_mmss(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; - else - last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ - } - /* As we return to user mode fire off the other CPU schedulers.. this is - basically because we don't yet share IRQ's around. This message is - rigged to be safe on the 386 - basically it's a hack, so don't look - closely for now.. */ - /*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */ - read_unlock (&xtime_lock); -} - -static inline void -r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - unsigned int count; + do_timer(regs); + + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. rtc_set_time() has to be + * called as close as possible to 500 ms before the new second starts. + */ + read_lock (&xtime_lock); + if ((time_status & STA_UNSYNC) == 0 && + xtime.tv_sec > last_rtc_update + 660 && + xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 && + xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) { + + if (rtc_set_time(xtime.tv_sec) == 0) { + last_rtc_update = xtime.tv_sec; + } else { + last_rtc_update = xtime.tv_sec - 600; + /* do it again in 60 s */ + } + } + read_unlock (&xtime_lock); /* - * The cycle counter is only 32 bit which is good for about - * a minute at current count rates of upto 150MHz or so. + * If jiffies has overflowed in this timer_interrupt we must + * update the timer[hi]/[lo] to make fast gettimeoffset funcs + * quotient calc still valid. -arca */ - count = read_32bit_cp0_register(CP0_COUNT); - timerhi += (count < timerlo); /* Wrap around */ - timerlo = count; - -#ifdef CONFIG_SGI_IP22 - /* Since we don't get anything but r4k timer interrupts, we need to - * set this up so that we'll get one next time. Fortunately since we - * have timerhi/timerlo, we don't care so much if we miss one. So - * we need only ask for the next in r4k_interval counts. On other - * archs we have a real timer, so we don't want this. - */ - write_32bit_cp0_register (CP0_COMPARE, - (unsigned long) (count + r4k_interval)); - kstat.irqs[0][irq]++; -#endif - - timer_interrupt(irq, dev_id, regs); - - if (!jiffies) - { - /* - * If jiffies has overflowed in this timer_interrupt we must - * update the timer[hi]/[lo] to make do_fast_gettimeoffset() - * quotient calc still valid. -arca - */ - timerhi = timerlo = 0; - } + if (!jiffies) { + timerhi = timerlo = 0; + } } -void indy_r4k_timer_interrupt (struct pt_regs *regs) +asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs) { - static const int INDY_R4K_TIMER_IRQ = 7; - r4k_timer_interrupt (INDY_R4K_TIMER_IRQ, NULL, regs); -} + int cpu = smp_processor_id(); -char cyclecounter_available; + irq_enter(cpu, irq); + kstat.irqs[cpu][irq]++; -static inline void init_cycle_counter(void) -{ - switch(mips_cputype) { - case CPU_UNKNOWN: - case CPU_R2000: - case CPU_R3000: - case CPU_R3000A: - case CPU_R3041: - case CPU_R3051: - case CPU_R3052: - case CPU_R3081: - case CPU_R3081E: - case CPU_R6000: - case CPU_R6000A: - case CPU_R8000: /* Not shure about that one, play safe */ - cyclecounter_available = 0; - break; - case CPU_R4000PC: - case CPU_R4000SC: - case CPU_R4000MC: - case CPU_R4200: - case CPU_R4400PC: - case CPU_R4400SC: - case CPU_R4400MC: - case CPU_R4600: - case CPU_R10000: - case CPU_R4300: - case CPU_R4650: - case CPU_R4700: - case CPU_R5000: - case CPU_R5000A: - case CPU_R4640: - case CPU_NEVADA: - cyclecounter_available = 1; - break; - } -} + /* we keep interrupt disabled all the time */ + timer_interrupt(irq, NULL, regs); + + irq_exit(cpu, irq); -struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, - "timer", NULL, NULL}; + /* check for bottom half */ + if (softirq_active(cpu)&softirq_mask(cpu)) + do_softirq(); +} -void (*board_time_init)(struct irqaction *irq); +/* + * time_init() - it does the following things. + * + * 1) board_time_init() - + * a) (optional) set up RTC routines, + * b) (optional) calibrate and set the mips_counter_frequency + * (only needed if you intended to use fixed_rate_gettimeoffset + * or use cpu counter as timer interrupt source) + * 2) setup xtime based on rtc_get_time(). + * 3) choose a appropriate gettimeoffset routine. + * 4) calculate a couple of cached variables for later usage + * 5) board_timer_setup() - + * a) (optional) over-write any choices made above by time_init(). + * b) machine specific code should setup the timer irqaction. + * c) enable the timer interrupt + */ + +void (*board_time_init)(void) = NULL; +void (*board_timer_setup)(struct irqaction *irq) = NULL; + +unsigned int mips_counter_frequency = 0; + +static struct irqaction timer_irqaction = { + timer_interrupt, + SA_INTERRUPT, + 0, + "timer", + NULL, + NULL}; void __init time_init(void) { - unsigned int epoch = 0, year, mon, day, hour, min, sec; - int i; + printk("New MIPS time_init() invoked.\n"); - /* The Linux interpretation of the CMOS clock register contents: - * When the Update-In-Progress (UIP) flag goes from 1 to 0, the - * RTC registers show the second which has precisely just started. - * Let's hope other operating systems interpret the RTC the same way. - */ - /* read RTC exactly on falling edge of update flag */ - for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) - break; - for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ - if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) - break; - do { /* Isn't this overkill ? UIP above should guarantee consistency */ - sec = CMOS_READ(RTC_SECONDS); - min = CMOS_READ(RTC_MINUTES); - hour = CMOS_READ(RTC_HOURS); - day = CMOS_READ(RTC_DAY_OF_MONTH); - mon = CMOS_READ(RTC_MONTH); - year = CMOS_READ(RTC_YEAR); - } while (sec != CMOS_READ(RTC_SECONDS)); - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - } - - /* Attempt to guess the epoch. This is the same heuristic as in rtc.c so - no stupid things will happen to timekeeping. Who knows, maybe Ultrix - also uses 1952 as epoch ... */ - if (year > 10 && year < 44) { - epoch = 1980; - } else if (year < 96) { - epoch = 1952; - } - year += epoch; + if (board_time_init) + board_time_init(); - write_lock_irq (&xtime_lock); - xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + /* setup xtime */ + write_lock_irq(&xtime_lock); + xtime.tv_sec = rtc_get_time(); xtime.tv_usec = 0; - write_unlock_irq (&xtime_lock); - - init_cycle_counter(); - - if (cyclecounter_available) { - write_32bit_cp0_register(CP0_COUNT, 0); - do_gettimeoffset = do_fast_gettimeoffset; - irq0.handler = r4k_timer_interrupt; + write_unlock_irq(&xtime_lock); + + /* choose appropriate gettimeoffset routine */ + if ( ! (mips_cpu.options & MIPS_CPU_COUNTER) ) { + /* no cpu counter - sorry */ + do_gettimeoffset = null_gettimeoffset; + } else if (mips_counter_frequency != 0) { + /* we have cpu counter and know counter frequency! */ + do_gettimeoffset = fixed_rate_gettimeoffset; + } else if ((mips_cpu.isa_level == MIPS_CPU_ISA_M32) || + (mips_cpu.isa_level == MIPS_CPU_ISA_I) || + (mips_cpu.isa_level == MIPS_CPU_ISA_II) ) { + /* we need to calibrate the counter but we don't have + * 64-bit division. */ + do_gettimeoffset = calibrate_div32_gettimeoffset; + } else { + /* we need to calibrate the counter but we *do* have + * 64-bit division. */ + do_gettimeoffset = calibrate_div64_gettimeoffset; + } + + /* caclulate cache parameters */ + if (mips_counter_frequency) { + cycles_per_jiffy = mips_counter_frequency / HZ; + + /* sll32_usecs_per_cycle = 10^6 * 2^32 / mips_counter_freq */ + /* any better way to do this? */ + sll32_usecs_per_cycle = mips_counter_frequency / 100000; + sll32_usecs_per_cycle = 0xffffffff / sll32_usecs_per_cycle; + sll32_usecs_per_cycle *= 10; + + MIPS_DEBUG(printk("cycles_per_jiffy = %d\n", + cycles_per_jiffy)); + MIPS_DEBUG(printk("sll32_usecs_per_cycle = %d \n", + sll32_usecs_per_cycle)); } - board_time_init(&irq0); + /* + * Call board specific timer interrupt setup. + * + * this pointer must be setup in machine setup routine. + * + * Even if the machine choose to use low-level timer interrupt, + * it still needs to setup the timer_irqaction. + * In that case, it might be better to set timer_irqaction.handler + * to be NULL function so that we are sure the high-level code + * is not invoked accidentally. + */ + MIPS_ASSERT(board_timer_setup != NULL); + board_timer_setup(&timer_irqaction); } diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 3bbbb2313d21..d51c33991f9b 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -32,6 +32,9 @@ #include <asm/system.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> +#ifndef CONFIG_MIPS_FPU_EMULATOR +#include <asm/inst.h> +#endif /* * Machine specific interrupt handlers @@ -90,9 +93,9 @@ void simulate_sc(struct pt_regs *regs, unsigned int opcode); #define RT 0x001f0000 #define OFFSET 0x0000ffff #define LL 0xc0000000 -#define SC 0xd0000000 +#define SC 0xe0000000 -#define DEBUG_LLSC +#undef DEBUG_LLSC #endif /* @@ -268,9 +271,6 @@ static void default_be_board_handler(struct pt_regs *regs) /* * Assume it would be too dangerous to continue ... */ -/* XXX */ -printk("Got Bus Error at %08x\n", (unsigned int)regs->cp0_epc); -show_regs(regs); while(1); force_sig(SIGBUS, current); } @@ -410,7 +410,7 @@ static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode) epc = (unsigned int *) (unsigned long) regs->cp0_epc; if (regs->cp0_cause & CAUSEF_BD) - epc += 4; + epc++; if (verify_area(VERIFY_READ, epc, 4)) { force_sig(SIGSEGV, current); @@ -423,6 +423,7 @@ static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode) void do_bp(struct pt_regs *regs) { + siginfo_t info; unsigned int opcode, bcode; /* @@ -491,48 +492,69 @@ void do_tr(struct pt_regs *regs) #if !defined(CONFIG_CPU_HAS_LLSC) +#ifdef CONFIG_SMP +#error "ll/sc emulation is not SMP safe" +#endif + /* * userland emulation for R2300 CPUs * needed for the multithreading part of glibc + * + * this implementation can handle only sychronization between 2 or more + * user contexts and is not SMP safe. */ void do_ri(struct pt_regs *regs) { unsigned int opcode; + if (!user_mode(regs)) + BUG(); + if (!get_insn_opcode(regs, &opcode)) { - if ((opcode & OPCODE) == LL) + if ((opcode & OPCODE) == LL) { simulate_ll(regs, opcode); - if ((opcode & OPCODE) == SC) + return; + } + if ((opcode & OPCODE) == SC) { simulate_sc(regs, opcode); - } else { - printk("[%s:%d] Illegal instruction at %08lx ra=%08lx\n", - current->comm, current->pid, regs->cp0_epc, regs->regs[31]); + return; + } } + printk("[%s:%d] Illegal instruction %08lx at %08lx, ra=%08lx, CP0_STATUS=%08lx\n", + current->comm, current->pid, *((unsigned long*)regs->cp0_epc), regs->cp0_epc, + regs->regs[31], regs->cp0_status); if (compute_return_epc(regs)) return; force_sig(SIGILL, current); } /* - * the ll_bit will be cleared by r2300_switch.S + * The ll_bit is cleared by r*_switch.S */ -unsigned long ll_bit, *lladdr; - + +unsigned long ll_bit; +#ifdef CONFIG_PROC_FS +extern unsigned long ll_ops; +extern unsigned long sc_ops; +#endif + +static struct task_struct *ll_task = NULL; + void simulate_ll(struct pt_regs *regp, unsigned int opcode) { - unsigned long *addr, *vaddr; + unsigned long value, *vaddr; long offset; - + int signal = 0; + /* * analyse the ll instruction that just caused a ri exception * and put the referenced address to addr. */ + /* sign extend offset */ offset = opcode & OFFSET; - if (offset & 0x00008000) - offset = -(offset & 0x00007fff); - else - offset = (offset & 0x00007fff); + offset <<= 16; + offset >>= 16; vaddr = (unsigned long *)((long)(regp->regs[(opcode & BASE) >> 21]) + offset); @@ -540,31 +562,44 @@ void simulate_ll(struct pt_regs *regp, unsigned int opcode) printk("ll: vaddr = 0x%08x, reg = %d\n", (unsigned int)vaddr, (opcode & RT) >> 16); #endif - /* - * TODO: compute physical address from vaddr - */ - panic("ll: emulation not yet finished!"); +#ifdef CONFIG_PROC_FS + ll_ops++; +#endif - lladdr = addr; - ll_bit = 1; - regp->regs[(opcode & RT) >> 16] = *addr; + if ((unsigned long)vaddr & 3) + signal = SIGBUS; + else if (get_user(value, vaddr)) + signal = SIGSEGV; + else { + if (ll_task == NULL || ll_task == current) { + ll_bit = 1; + } else { + ll_bit = 0; + } + ll_task = current; + regp->regs[(opcode & RT) >> 16] = value; + } + if (compute_return_epc(regp)) + return; + if (signal) + send_sig(signal, current, 1); } - + void simulate_sc(struct pt_regs *regp, unsigned int opcode) { - unsigned long *addr, *vaddr, reg; + unsigned long *vaddr, reg; long offset; + int signal = 0; /* * analyse the sc instruction that just caused a ri exception * and put the referenced address to addr. */ + /* sign extend offset */ offset = opcode & OFFSET; - if (offset & 0x00008000) - offset = -(offset & 0x00007fff); - else - offset = (offset & 0x00007fff); + offset <<= 16; + offset >>= 16; vaddr = (unsigned long *)((long)(regp->regs[(opcode & BASE) >> 21]) + offset); reg = (opcode & RT) >> 16; @@ -573,28 +608,34 @@ void simulate_sc(struct pt_regs *regp, unsigned int opcode) printk("sc: vaddr = 0x%08x, reg = %d\n", (unsigned int)vaddr, (unsigned int)reg); #endif - /* - * TODO: compute physical address from vaddr - */ - panic("sc: emulation not yet finished!"); - - lladdr = addr; +#ifdef CONFIG_PROC_FS + sc_ops++; +#endif - if (ll_bit == 0) { + if ((unsigned long)vaddr & 3) + signal = SIGBUS; + else if (ll_bit == 0 || ll_task != current) regp->regs[reg] = 0; + else if (put_user(regp->regs[reg], vaddr)) + signal = SIGSEGV; + else + regp->regs[reg] = 1; + if (compute_return_epc(regp)) return; - } - - *addr = regp->regs[reg]; - regp->regs[reg] = 1; + if (signal) + send_sig(signal, current, 1); } #else /* MIPS 2 or higher */ void do_ri(struct pt_regs *regs) { - printk("[%s:%d] Illegal instruction at %08lx ra=%08lx\n", - current->comm, current->pid, regs->cp0_epc, regs->regs[31]); + unsigned int opcode; + + get_insn_opcode(regs, &opcode); + printk("[%s:%ld] Illegal instruction %08x at %08lx ra=%08lx\n", + current->comm, (unsigned long)current->pid, opcode, + regs->cp0_epc, regs->regs[31]); if (compute_return_epc(regs)) return; force_sig(SIGILL, current); @@ -662,50 +703,101 @@ void do_watch(struct pt_regs *regs) panic("Caught WATCH exception - probably caused by stack overflow."); } +void do_mcheck(struct pt_regs *regs) +{ + show_regs(regs); + panic("Caught Machine Check exception - probably caused by multiple " + "matching entries in the TLB."); +} + void do_reserved(struct pt_regs *regs) { /* - * Game over - no way to handle this if it ever occurs. - * Most probably caused by a new unknown cpu type or - * after another deadly hard/software error. + * Game over - no way to handle this if it ever occurs. Most probably + * caused by a new unknown cpu type or after another deadly + * hard/software error. */ + show_regs(regs); panic("Caught reserved exception - should not happen."); } -static inline void watch_init(unsigned long cputype) +static inline void watch_init(void) { - switch(cputype) { - case CPU_R10000: - case CPU_R4000MC: - case CPU_R4400MC: - case CPU_R4000SC: - case CPU_R4400SC: - case CPU_R4000PC: - case CPU_R4400PC: - case CPU_R4200: - case CPU_R4300: - set_except_vector(23, handle_watch); - watch_available = 1; - break; - } + if(mips_cpu.options & MIPS_CPU_WATCH ) { + (void)set_except_vector(23, handle_watch); + watch_available = 1; + } } /* * Some MIPS CPUs have a dedicated interrupt vector which reduces the * interrupt processing overhead. Use it where available. - * FIXME: more CPUs than just the Nevada have this feature. */ static inline void setup_dedicated_int(void) { extern void except_vec4(void); - switch(mips_cputype) { - case CPU_NEVADA: + + if(mips_cpu.options & MIPS_CPU_DIVEC) { memcpy((void *)(KSEG0 + 0x200), except_vec4, 8); - set_cp0_cause(CAUSEF_IV, CAUSEF_IV); + set_cp0_cause(CAUSEF_IV); dedicated_iv_available = 1; } } +/* + * Some MIPS CPUs can enable/disable for cache parity detection, but does + * it different ways. + */ +static inline void parity_protection_init(void) +{ + switch(mips_cpu.cputype) { + case CPU_5KC: + /* Set the PE bit (bit 31) in the CP0_ECC register. */ + printk(KERN_INFO "Enable the cache parity protection for " + "MIPS 5KC CPUs.\n"); + write_32bit_cp0_register(CP0_ECC, + read_32bit_cp0_register(CP0_ECC) + | 0x80000000); + break; + default: + break; + } +} + +void cache_parity_error(void) +{ + unsigned int reg_val; + + /* For the moment, report the problem and hang. */ + reg_val = read_32bit_cp0_register(CP0_ERROREPC); + printk("Cache error exception:\n"); + printk("cp0_errorepc == %08x\n", reg_val); + reg_val = read_32bit_cp0_register(CP0_CACHEERR); + printk("cp0_cacheerr == %08x\n", reg_val); + + printk("Decoded CP0_CACHEERR: %s cache fault in %s reference.\n", + reg_val&(1<<30)?"secondary":"primary", + reg_val&(1<<31)?"data":"insn"); + printk("Error bits: %s%s%s%s%s%s%s\n", + reg_val&(1<<29)?"ED ":"", + reg_val&(1<<28)?"ET ":"", + reg_val&(1<<26)?"EE ":"", + reg_val&(1<<25)?"EB ":"", + reg_val&(1<<24)?"EI ":"", + reg_val&(1<<23)?"E1 ":"", + reg_val&(1<<22)?"E0 ":""); + printk("IDX: 0x%08x\n", reg_val&((1<<22)-1)); + + if (reg_val&(1<<22)) + printk("DErrAddr0: 0x%08x\n", read_32bit_cp0_set1_register(CP0_S1_DERRADDR0)); + + if (reg_val&(1<<23)) + printk("DErrAddr1: 0x%08x\n", read_32bit_cp0_set1_register(CP0_S1_DERRADDR1)); + + + panic("Can't handle the cache error - panic!"); +} + unsigned long exception_handlers[32]; /* @@ -713,23 +805,36 @@ unsigned long exception_handlers[32]; * to interrupt handlers in the address range from * KSEG0 <= x < KSEG0 + 256mb on the Nevada. Oh well ... */ -void set_except_vector(int n, void *addr) +void *set_except_vector(int n, void *addr) { unsigned handler = (unsigned long) addr; + unsigned old_handler = exception_handlers[n]; exception_handlers[n] = handler; if (n == 0 && dedicated_iv_available) { *(volatile u32 *)(KSEG0+0x200) = 0x08000000 | (0x03ffffff & (handler >> 2)); flush_icache_range(KSEG0+0x200, KSEG0 + 0x204); } + return (void *)old_handler; } +asmlinkage int (*save_fp_context)(struct sigcontext *sc); +asmlinkage int (*restore_fp_context)(struct sigcontext *sc); +extern asmlinkage int _save_fp_context(struct sigcontext *sc); +extern asmlinkage int _restore_fp_context(struct sigcontext *sc); + +#ifdef CONFIG_MIPS_FPU_EMULATOR +extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc); +extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc); +#endif + void __init trap_init(void) { extern char except_vec0_nevada, except_vec0_r4000; extern char except_vec0_r4600, except_vec0_r2300; extern char except_vec1_generic, except_vec2_generic; extern char except_vec3_generic, except_vec3_r4000; + extern char except_vec_ejtag_debug; unsigned long i; if(mips_machtype == MACH_MIPS_MAGNUM_4000 || @@ -737,101 +842,121 @@ void __init trap_init(void) EISA_bus = 1; /* Some firmware leaves the BEV flag set, clear it. */ - set_cp0_status(ST0_BEV, 0); + clear_cp0_status(ST0_BEV); /* Copy the generic exception handler code to it's final destination. */ memcpy((void *)(KSEG0 + 0x80), &except_vec1_generic, 0x80); memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80); memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic, 0x80); - + flush_icache_range(KSEG0 + 0x80, KSEG0 + 0x200); /* * Setup default vectors */ for(i = 0; i <= 31; i++) - set_except_vector(i, handle_reserved); + (void)set_except_vector(i, handle_reserved); + + /* + * Copy the EJTAG debug exception vector handler code to it's final + * destination. + */ + memcpy((void *)(KSEG0 + 0x300), &except_vec_ejtag_debug, 0x80); /* * Only some CPUs have the watch exceptions or a dedicated * interrupt vector. */ - watch_init(mips_cputype); + watch_init(); setup_dedicated_int(); - set_except_vector(1, handle_mod); - set_except_vector(2, handle_tlbl); - set_except_vector(3, handle_tlbs); - set_except_vector(4, handle_adel); - set_except_vector(5, handle_ades); + /* + * Some CPUs can enable/disable for cache parity detection, but does + * it different ways. + */ + parity_protection_init(); + + (void)set_except_vector(1, handle_mod); + (void)set_except_vector(2, handle_tlbl); + (void)set_except_vector(3, handle_tlbs); + (void)set_except_vector(4, handle_adel); + (void)set_except_vector(5, handle_ades); /* * The Data Bus Error/ Instruction Bus Errors are signaled * by external hardware. Therefore these two expection have * board specific handlers. */ - set_except_vector(6, handle_ibe); - set_except_vector(7, handle_dbe); + (void)set_except_vector(6, handle_ibe); + (void)set_except_vector(7, handle_dbe); ibe_board_handler = default_be_board_handler; dbe_board_handler = default_be_board_handler; - set_except_vector(8, handle_sys); - set_except_vector(9, handle_bp); - set_except_vector(10, handle_ri); - set_except_vector(11, handle_cpu); - set_except_vector(12, handle_ov); - set_except_vector(13, handle_tr); - set_except_vector(15, handle_fpe); - + (void)set_except_vector(8, handle_sys); + (void)set_except_vector(9, handle_bp); + (void)set_except_vector(10, handle_ri); + (void)set_except_vector(11, handle_cpu); + (void)set_except_vector(12, handle_ov); + (void)set_except_vector(13, handle_tr); + (void)set_except_vector(15, handle_fpe); + /* * Handling the following exceptions depends mostly of the cpu type */ - switch(mips_cputype) { - case CPU_R10000: - /* - * The R10000 is in most aspects similar to the R4400. It - * should get some special optimizations. - */ - write_32bit_cp0_register(CP0_FRAMEMASK, 0); - set_cp0_status(ST0_XX, ST0_XX); - /* - * The R10k might even work for Linux/MIPS - but we're paranoid - * and refuse to run until this is tested on real silicon - */ - panic("CPU too expensive - making holiday in the ANDES!"); - break; - case CPU_R4000MC: - case CPU_R4400MC: - case CPU_R4000SC: - case CPU_R4400SC: - vce_available = 1; - /* Fall through ... */ - case CPU_R4000PC: - case CPU_R4400PC: - case CPU_R4200: - case CPU_R4300: - /* case CPU_R4640: */ - case CPU_R4600: - case CPU_R5000: - case CPU_NEVADA: - if(mips_cputype == CPU_NEVADA) { + if ((mips_cpu.options & MIPS_CPU_4KEX) + && (mips_cpu.options & MIPS_CPU_4KTLB)) { + if(mips_cpu.cputype == CPU_NEVADA) { memcpy((void *)KSEG0, &except_vec0_nevada, 0x80); - } else if (mips_cputype == CPU_R4600) + } else if (mips_cpu.cputype == CPU_R4600) memcpy((void *)KSEG0, &except_vec0_r4600, 0x80); else memcpy((void *)KSEG0, &except_vec0_r4000, 0x80); /* Cache error vector already set above. */ - if (vce_available) { + if (mips_cpu.options & MIPS_CPU_VCE) { memcpy((void *)(KSEG0 + 0x180), &except_vec3_r4000, 0x80); } else { memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic, 0x80); } - break; + if(mips_cpu.options & MIPS_CPU_FPU) { + save_fp_context = _save_fp_context; + restore_fp_context = _restore_fp_context; +#ifdef CONFIG_MIPS_FPU_EMULATOR + } else { + save_fp_context = fpu_emulator_save_context; + restore_fp_context = fpu_emulator_restore_context; +#endif + } + } else switch(mips_cpu.cputype) { + case CPU_R10000: + /* + * The R10000 is in most aspects similar to the R4400. It + * should get some special optimizations. + */ + write_32bit_cp0_register(CP0_FRAMEMASK, 0); + set_cp0_status(ST0_XX); + /* + * The R10k might even work for Linux/MIPS - but we're paranoid + * and refuse to run until this is tested on real silicon + */ + panic("CPU too expensive - making holiday in the ANDES!"); + break; + case CPU_SB1: + /* XXX - This should be folded in to the "cleaner" handling, above */ + memcpy((void *)KSEG0, &except_vec0_r4000, 0x80); + memcpy((void *)(KSEG0 + 0x180), &except_vec3_r4000, 0x80); + save_fp_context = _save_fp_context; + restore_fp_context = _restore_fp_context; + /* Enable timer interrupt and scd mapped interrupt in status register */ + clear_cp0_status(0xf000); + set_cp0_status(0xc00); + break; case CPU_R6000: case CPU_R6000A: -#if 0 + save_fp_context = _save_fp_context; + restore_fp_context = _restore_fp_context; + /* * The R6000 is the only R-series CPU that features a machine * check exception (similar to the R4000 cache error) and @@ -840,9 +965,8 @@ void __init trap_init(void) * current list of targets for Linux/MIPS. * (Duh, crap, there is someone with a tripple R6k machine) */ - set_except_vector(14, handle_mc); - set_except_vector(15, handle_ndc); -#endif + //set_except_vector(14, handle_mc); + //set_except_vector(15, handle_ndc); case CPU_R2000: case CPU_R3000: case CPU_R3000A: @@ -851,12 +975,17 @@ void __init trap_init(void) case CPU_R3052: case CPU_R3081: case CPU_R3081E: + case CPU_TX3912: + case CPU_TX3922: + case CPU_TX3927: + save_fp_context = _save_fp_context; + restore_fp_context = _restore_fp_context; memcpy((void *)KSEG0, &except_vec0_r2300, 0x80); memcpy((void *)(KSEG0 + 0x80), &except_vec3_generic, 0x80); break; case CPU_R8000: printk("Detected unsupported CPU type %s.\n", - cpu_names[mips_cputype]); + cpu_names[mips_cpu.cputype]); panic("Can't handle CPU"); break; @@ -868,5 +997,6 @@ void __init trap_init(void) atomic_inc(&init_mm.mm_count); /* XXX UP? */ current->active_mm = &init_mm; - current_pgd = init_mm.pgd; + write_32bit_cp0_register(CP0_CONTEXT, smp_processor_id()<<23); + current_pgd[0] = init_mm.pgd; } diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 9953922b7395..9325c9519664 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -1,5 +1,4 @@ -/* $Id: unaligned.c,v 1.7 1999/12/04 03:59:00 ralf Exp $ - * +/* * Handle unaligned accesses by emulation. * * This file is subject to the terms and conditions of the GNU General Public @@ -83,6 +82,7 @@ #include <asm/byteorder.h> #include <asm/inst.h> #include <asm/uaccess.h> +#include <asm/system.h> #define STR(x) __STR(x) #define __STR(x) #x @@ -91,8 +91,8 @@ * User code may only access USEG; kernel code may access the * entire address space. */ -#define check_axs(p,a,s) \ - if ((long)(~(pc) & ((a) | ((a)+(s)))) < 0) \ +#define check_axs(pc,a,s) \ + if ((long)(~(pc) & ((a) | ((a)+(s)))) < 0) \ goto sigbus; static inline void @@ -365,12 +365,15 @@ fault: return; } + die_if_kernel ("Unhandled kernel unaligned access", regs); send_sig(SIGSEGV, current, 1); return; sigbus: + die_if_kernel ("Unhandled kernel unaligned access", regs); send_sig(SIGBUS, current, 1); return; sigill: + die_if_kernel ("Unhandled kernel unaligned access or invalid instruction", regs); send_sig(SIGILL, current, 1); return; } @@ -380,6 +383,21 @@ unsigned long unaligned_instructions; asmlinkage void do_ade(struct pt_regs *regs) { unsigned long pc; +#ifdef CONFIG_MIPS_FPU_EMULATOR + extern int do_dsemulret(struct pt_regs *); + + /* + * Address errors may be deliberately induced + * by the FPU emulator to take retake control + * of the CPU after executing the instruction + * in the delay slot of an emulated branch. + */ + + if((unsigned long)regs->cp0_epc == current->thread.dsemul_aerpc) { + (void)do_dsemulret(regs); + return; + } +#endif /* CONFIG_MIPS_FPU_EMULATOR */ /* * Did we catch a fault trying to load an instruction? @@ -401,6 +419,7 @@ asmlinkage void do_ade(struct pt_regs *regs) return; sigbus: + die_if_kernel ("Kernel unaligned instruction access", regs); force_sig(SIGBUS, current); return; diff --git a/arch/mips/ld.script.big b/arch/mips/ld.script.in index 27a5bade56ed..b8cbfd6e6504 100644 --- a/arch/mips/ld.script.big +++ b/arch/mips/ld.script.in @@ -1,10 +1,9 @@ -OUTPUT_FORMAT("elf32-bigmips") OUTPUT_ARCH(mips) ENTRY(kernel_entry) SECTIONS { /* Read-only sections, merged into text segment: */ - . = 0x80000000; + . = @@LOADADDR@@; .init : { *(.init) } =0 .text : { @@ -15,8 +14,22 @@ SECTIONS /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) } =0 + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___dbe_table = .; /* Exception table for data bus errors */ + __dbe_table : { *(__dbe_table) } + __stop___dbe_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + _etext = .; - PROVIDE (etext = .); . = ALIGN(8192); .data.init_task : { *(.data.init_task) } @@ -63,6 +76,14 @@ SECTIONS { _fdata = . ; *(.data) + + /* Align the initial ramdisk image (INITRD) on page boundaries. */ + . = ALIGN(4096); + __rd_start = .; + *(.initrd) + __rd_end = .; + . = ALIGN(4096); + CONSTRUCTORS } .data1 : { *(.data1) } @@ -77,6 +98,7 @@ SECTIONS can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ .sdata : { *(.sdata) } + . = ALIGN(4); _edata = .; PROVIDE (edata = .); @@ -88,6 +110,7 @@ SECTIONS *(.dynbss) *(.bss) *(COMMON) + . = ALIGN(4); _end = . ; PROVIDE (end = .); } @@ -100,6 +123,8 @@ SECTIONS *(.exitcall.exit) } + /* This is the MIPS specific mdebug section. */ + .mdebug : { *(.mdebug) } /* These are needed for ELF backends which have not yet been converted to the new style linker. */ .stab 0 : { *(.stab) } @@ -117,4 +142,6 @@ SECTIONS /* These must appear regardless of . */ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } + .comment : { *(.comment) } + .note : { *(.note) } } diff --git a/arch/mips/ld.script.little b/arch/mips/ld.script.little deleted file mode 100644 index 48f9bc5fe6f1..000000000000 --- a/arch/mips/ld.script.little +++ /dev/null @@ -1,120 +0,0 @@ -OUTPUT_FORMAT("elf32-littlemips") -OUTPUT_ARCH(mips) -ENTRY(kernel_entry) -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = 0x80000000; - .init : { *(.init) } =0 - .text : - { - _ftext = . ; - *(.text) - *(.rodata) - *(.rodata1) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } =0 - _etext = .; - PROVIDE (etext = .); - - . = ALIGN(8192); - .data.init_task : { *(.data.init_task) } - - /* Startup code */ - . = ALIGN(4096); - __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } - . = ALIGN(16); - __setup_start = .; - .setup.init : { *(.setup.init) } - __setup_end = .; - __initcall_start = .; - .initcall.init : { *(.initcall.init) } - __initcall_end = .; - . = ALIGN(4096); /* Align double page for init_task_union */ - __init_end = .; - - . = ALIGN(4096); - .data.page_aligned : { *(.data.idt) } - - . = ALIGN(32); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } - - .fini : { *(.fini) } =0 - .reginfo : { *(.reginfo) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. It would - be more correct to do this: - . = .; - The current expression does not correctly handle the case of a - text segment ending precisely at the end of a page; it causes the - data segment to skip a page. The above expression does not have - this problem, but it will currently (2/95) cause BFD to allocate - a single segment, combining both text and data, for this case. - This will prevent the text segment from being shared among - multiple executions of the program; I think that is more - important than losing a page of the virtual address space (note - that no actual memory is lost; the page which is skipped can not - be referenced). */ - . = .; - .data : - { - _fdata = . ; - *(.data) - CONSTRUCTORS - } - .data1 : { *(.data1) } - _gp = . + 0x8000; - .lit8 : { *(.lit8) } - .lit4 : { *(.lit4) } - .ctors : { *(.ctors) } - .dtors : { *(.dtors) } - .got : { *(.got.plt) *(.got) } - .dynamic : { *(.dynamic) } - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : { *(.sdata) } - _edata = .; - PROVIDE (edata = .); - - __bss_start = .; - _fbss = .; - .sbss : { *(.sbss) *(.scommon) } - .bss : - { - *(.dynbss) - *(.bss) - *(COMMON) - _end = . ; - PROVIDE (end = .); - } - - /* Sections to be discarded */ - /DISCARD/ : - { - *(.text.exit) - *(.data.exit) - *(.exitcall.exit) - } - - /* These are needed for ELF backends which have not yet been - converted to the new style linker. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - /* DWARF debug sections. - Symbols in the .debug DWARF section are relative to the beginning of the - section so we begin .debug at 0. It's not clear yet what needs to happen - for the others. */ - .debug 0 : { *(.debug) } - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - .debug_sfnames 0 : { *(.debug_sfnames) } - .line 0 : { *(.line) } - /* These must appear regardless of . */ - .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } - .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } -} diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index b51696301a72..8d2a4540621d 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -17,11 +17,7 @@ obj-y += csum_partial.o csum_partial_copy.o \ ifdef CONFIG_CPU_R3000 obj-y += r3k_dump_tlb.o else - ifdef CONFIG_CPU_R3912 - obj-y += r3k_dump_tlb.o - else - obj-y += dump_tlb.o - endif + obj-y += dump_tlb.o endif obj-$(CONFIG_BLK_DEV_FD) += floppy-no.o floppy-std.o diff --git a/arch/mips/lib/kbd-std.c b/arch/mips/lib/kbd-std.c index 3a50c89d0da7..ecaa2a0d88ab 100644 --- a/arch/mips/lib/kbd-std.c +++ b/arch/mips/lib/kbd-std.c @@ -8,7 +8,6 @@ * * Copyright (C) 1998, 1999 by Ralf Baechle */ -#include <linux/config.h> #include <linux/ioport.h> #include <linux/sched.h> #include <linux/pc_keyb.h> @@ -21,7 +20,6 @@ static void std_kbd_request_region(void) { #ifdef CONFIG_MIPS_ITE8172 - printk("std_kbd_request_region\n"); request_region(0x14000060, 16, "keyboard"); #else request_region(0x60, 16, "keyboard"); @@ -30,7 +28,6 @@ static void std_kbd_request_region(void) static int std_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *)) { - printk("std_kbd_request_irq\n"); return request_irq(KEYBOARD_IRQ, handler, 0, "keyboard", NULL); } diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index 0340cc2a143a..5868db88c8be 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -54,6 +54,7 @@ LEAF(memset) 1: EXPORT(__bzero) + .type __bzero, @function sltiu t0, a2, 4 /* very small region? */ bnez t0, small_memset andi t0, a0, 3 /* aligned? */ diff --git a/arch/mips/lib/rtc-no.c b/arch/mips/lib/rtc-no.c index 7f0c02e18459..f8a9b2bd29fa 100644 --- a/arch/mips/lib/rtc-no.c +++ b/arch/mips/lib/rtc-no.c @@ -1,5 +1,4 @@ -/* $Id: rtc-no.c,v 1.2 1998/06/25 20:19:15 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -7,28 +6,25 @@ * Stub RTC routines to keep Linux from crashing on machine which don't * have a RTC chip. * - * Copyright (C) 1998 by Ralf Baechle + * Copyright (C) 1998, 2001 by Ralf Baechle */ #include <linux/kernel.h> #include <linux/mc146818rtc.h> -static unsigned char no_rtc_read_data(unsigned long addr) +static unsigned int shouldnt_happen(void) { - panic("no_rtc_read_data called - shouldn't happen."); -} + static int called; -static void no_rtc_write_data(unsigned char data, unsigned long addr) -{ - panic("no_rtc_write_data called - shouldn't happen."); -} + if (!called) { + called = 1; + printk(KERN_DEBUG "RTC functions called - shouldn't happen\n"); + } -static int no_rtc_bcd_mode(void) -{ - panic("no_rtc_bcd_mode called - shouldn't happen."); + return 0; } struct rtc_ops no_rtc_ops = { - &no_rtc_read_data, - &no_rtc_write_data, - &no_rtc_bcd_mode + rtc_read_data: (void *) &shouldnt_happen, + rtc_write_data: (void *) &shouldnt_happen, + rtc_bcd_mode: (void *) &shouldnt_happen }; diff --git a/arch/mips/lib/rtc-std.c b/arch/mips/lib/rtc-std.c index a601d1879178..e36d02d22777 100644 --- a/arch/mips/lib/rtc-std.c +++ b/arch/mips/lib/rtc-std.c @@ -1,12 +1,11 @@ -/* $Id: rtc-std.c,v 1.2 1998/06/25 20:19:16 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * RTC routines for PC style attached Dallas chip. * - * Copyright (C) 1998 by Ralf Baechle + * Copyright (C) 1998, 2001 by Ralf Baechle */ #include <linux/mc146818rtc.h> #include <asm/io.h> diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index b0147eb9825b..4be4633c659c 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -49,6 +49,7 @@ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. *************************************************************************/ +#include <linux/config.h> #include <linux/mm.h> #include <linux/signal.h> #include <linux/smp.h> diff --git a/arch/mips/math-emu/dp_sub.c b/arch/mips/math-emu/dp_sub.c index 198e5609859c..a56d352fc156 100644 --- a/arch/mips/math-emu/dp_sub.c +++ b/arch/mips/math-emu/dp_sub.c @@ -176,11 +176,12 @@ ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) xe = xe; xs = ys; } - if (xm == 0) + if (xm == 0) { if (ieee754_csr.rm == IEEE754_RD) return ieee754dp_zero(1); /* round negative inf. => sign = -1 */ else return ieee754dp_zero(0); /* other round modes => sign = 1 */ + } /* normalize to rounding precision */ diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index 16ed11ac75b5..aa1d667f55de 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -9,11 +9,10 @@ O_TARGET := mm.o -export-objs += umap.o -obj-y += extable.o init.o fault.o loadmmu.o +export-objs += ioremap.o umap.o +obj-y += extable.o init.o ioremap.o fault.o loadmmu.o obj-$(CONFIG_CPU_R3000) += r2300.o -obj-$(CONFIG_CPU_R3912) += r2300.o obj-$(CONFIG_CPU_R4300) += r4xx0.o obj-$(CONFIG_CPU_R4X00) += r4xx0.o obj-$(CONFIG_CPU_R5000) += r4xx0.o diff --git a/arch/mips/tools/offset.c b/arch/mips/tools/offset.c index e691b6d71adb..7df4a6c1dcc0 100644 --- a/arch/mips/tools/offset.c +++ b/arch/mips/tools/offset.c @@ -1,12 +1,13 @@ -/* $Id: offset.c,v 1.11 1999/09/28 22:25:50 ralf Exp $ - * +/* * offset.c: Calculate pt_regs and task_struct offsets. * * Copyright (C) 1996 David S. Miller * Copyright (C) 1997, 1998, 1999 Ralf Baechle * Copyright (C) 1999 Silicon Graphics, Inc. + * + * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. */ - #include <linux/types.h> #include <linux/sched.h> @@ -84,6 +85,7 @@ void output_task_defines(void) offset("#define TASK_COUNTER ", struct task_struct, counter); offset("#define TASK_NICE ", struct task_struct, nice); offset("#define TASK_MM ", struct task_struct, mm); + offset("#define TASK_PID ", struct task_struct, pid); size("#define TASK_STRUCT_SIZE ", struct task_struct); linefeed; } @@ -119,6 +121,10 @@ void output_thread_defines(void) thread.irix_trampoline); offset("#define THREAD_OLDCTX ", struct task_struct, \ thread.irix_oldctx); + offset("#define THREAD_DSEEPC ", struct task_struct, \ + thread.dsemul_epc); + offset("#define THREAD_DSEAERPC ", struct task_struct, \ + thread.dsemul_aerpc); linefeed; } diff --git a/arch/mips64/ld.script.elf32.S b/arch/mips64/ld.script.elf32.S index c3564803d841..3a00edf0aa54 100644 --- a/arch/mips64/ld.script.elf32.S +++ b/arch/mips64/ld.script.elf32.S @@ -8,6 +8,7 @@ SECTIONS { *(.text) *(.rodata) + *(.rodata.*) *(.rodata1) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) diff --git a/arch/mips64/ld.script.elf64 b/arch/mips64/ld.script.elf64 index 55460d07edef..d7c3c94539a8 100644 --- a/arch/mips64/ld.script.elf64 +++ b/arch/mips64/ld.script.elf64 @@ -18,6 +18,7 @@ SECTIONS .text : { *(.text) *(.rodata) + *(.rodata.*) *(.rodata1) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) diff --git a/arch/mips64/math-emu/Makefile b/arch/mips64/math-emu/Makefile new file mode 100644 index 000000000000..9a6b054fd56d --- /dev/null +++ b/arch/mips64/math-emu/Makefile @@ -0,0 +1,24 @@ +# +# Makefile for the Linux/MIPS kernel FPU emulation. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +EXTRA_ASFLAGS = -mips2 -mcpu=r4000 + +O_TARGET:= fpu_emulator.o + +obj-y := cp1emu.o ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \ + ieee754xcpt.o dp_frexp.o dp_modf.o dp_div.o dp_mul.o dp_sub.o \ + dp_add.o dp_fsp.o dp_cmp.o dp_logb.o dp_scalb.o dp_simple.o \ + dp_tint.o dp_fint.o dp_tlong.o dp_flong.o sp_frexp.o sp_modf.o \ + sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_logb.o \ + sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \ + dp_sqrt.o sp_sqrt.o kernel_linkage.o + +include $(TOPDIR)/Rules.make diff --git a/arch/mips64/math-emu/cp1emu.c b/arch/mips64/math-emu/cp1emu.c new file mode 100644 index 000000000000..d48f9cc39c94 --- /dev/null +++ b/arch/mips64/math-emu/cp1emu.c @@ -0,0 +1,1807 @@ +/* + * MIPS floating point support + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator + * + * A complete emulator for MIPS coprocessor 1 instructions. This is + * required for #float(switch) or #float(trap), where it catches all + * COP1 instructions via the "CoProcessor Unusable" exception. + * + * More surprisingly it is also required for #float(ieee), to help out + * the hardware fpu at the boundaries of the IEEE-754 representation + * (denormalised values, infinities, underflow, etc). It is made + * quite nasty because emulation of some non-COP1 instructions is + * required, e.g. in branch delay slots. + * + * Notes: + * 1) the IEEE754 library (-le) performs the actual arithmetic; + * 2) if you know that you won't have an fpu, then you'll get much + * better performance by compiling with -msoft-float! */ + * + * Nov 7, 2000 + * Massive changes to integrate with Linux kernel. + * + * Replace use of kernel data area with use of user stack + * for execution of instructions in branch delay slots. + * + * Replace use of static kernel variables with thread_struct elements. + * + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/config.h> +#include <linux/mm.h> +#include <linux/signal.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> + +#include <asm/asm.h> +#include <asm/branch.h> +#include <asm/byteorder.h> +#include <asm/inst.h> +#include <asm/uaccess.h> +#include <asm/processor.h> +#include <asm/mipsregs.h> +#include <asm/system.h> +#include <asm/pgtable.h> + +#include <asm/fpu_emulator.h> + +#include "ieee754.h" + +/* Strap kernel emulator for full MIPS IV emulation */ + +#ifdef __mips +#undef __mips +#endif +#define __mips 4 + +typedef void *vaddr_t; + +/* Function which emulates the instruction in a branch delay slot. */ + +static int mips_dsemul(struct pt_regs *, mips_instruction, vaddr_t); + +/* Function which emulates a floating point instruction. */ + +static int fpu_emu(struct pt_regs *, struct mips_fpu_soft_struct *, + mips_instruction); + +#if __mips >= 4 && __mips != 32 +static int fpux_emu(struct pt_regs *, + struct mips_fpu_soft_struct *, mips_instruction); +#endif + +/* Further private data for which no space exists in mips_fpu_soft_struct */ + +struct mips_fpu_emulator_private fpuemuprivate; + +/* Control registers */ + +#define FPCREG_RID 0 /* $0 = revision id */ +#define FPCREG_CSR 31 /* $31 = csr */ + +/* Convert Mips rounding mode (0..3) to IEEE library modes. */ +static const unsigned char ieee_rm[4] = { + IEEE754_RN, IEEE754_RZ, IEEE754_RU, IEEE754_RD +}; + +#if __mips >= 4 +/* convert condition code register number to csr bit */ +static const unsigned int fpucondbit[8] = { + FPU_CSR_COND0, + FPU_CSR_COND1, + FPU_CSR_COND2, + FPU_CSR_COND3, + FPU_CSR_COND4, + FPU_CSR_COND5, + FPU_CSR_COND6, + FPU_CSR_COND7 +}; +#endif + + + +/* + * Redundant with logic already in kernel/branch.c, + * embedded in compute_return_epc. At some point, + * a single subroutine should be used across both + * modules. + */ +static int isBranchInstr(mips_instruction * i) +{ + switch (MIPSInst_OPCODE(*i)) { + case spec_op: + switch (MIPSInst_FUNC(*i)) { + case jalr_op: + case jr_op: + return 1; + } + break; + + case bcond_op: + switch (MIPSInst_RT(*i)) { + case bltz_op: + case bgez_op: + case bltzl_op: + case bgezl_op: + case bltzal_op: + case bgezal_op: + case bltzall_op: + case bgezall_op: + return 1; + } + break; + + case j_op: + case jal_op: + case jalx_op: + case beq_op: + case bne_op: + case blez_op: + case bgtz_op: + case beql_op: + case bnel_op: + case blezl_op: + case bgtzl_op: + return 1; + + case cop0_op: + case cop1_op: + case cop2_op: + case cop1x_op: + if (MIPSInst_RS(*i) == bc_op) + return 1; + break; + } + + return 0; +} + +#define REG_TO_VA (vaddr_t) +#define VA_TO_REG (unsigned long) + +static unsigned long +mips_get_word(struct pt_regs *xcp, void *va, int *perr) +{ + unsigned long temp; + + if (!user_mode(xcp)) { + *perr = 0; + return (*(unsigned long *) va); + } else { + /* Use kernel get_user() macro */ + *perr = (int) get_user(temp, (unsigned long *) va); + return temp; + } +} + +static unsigned long long +mips_get_dword(struct pt_regs *xcp, void *va, int *perr) +{ + unsigned long long temp; + + if (!user_mode(xcp)) { + *perr = 0; + return (*(unsigned long long *) va); + } else { + /* Use kernel get_user() macro */ + *perr = (int) get_user(temp, (unsigned long long *) va); + return temp; + } +} + +static int mips_put_word(struct pt_regs *xcp, void *va, unsigned long val) +{ + if (!user_mode(xcp)) { + *(unsigned long *) va = val; + return 0; + } else { + /* Use kernel get_user() macro */ + return (int) put_user(val, (unsigned long *) va); + } +} + +static int mips_put_dword(struct pt_regs *xcp, void *va, long long val) +{ + if (!user_mode(xcp)) { + *(unsigned long long *) va = val; + return 0; + } else { + /* Use kernel get_user() macro */ + return (int) put_user(val, (unsigned long long *) va); + } +} + + +/* + * In the Linux kernel, we support selection of FPR format on the + * basis of the Status.FR bit. This does imply that, if a full 32 + * FPRs are desired, there needs to be a flip-flop that can be written + * to one at that bit position. In any case, normal MIPS ABI uses + * only the even FPRs (Status.FR = 0). + */ + +#define CP0_STATUS_FR_SUPPORT + +/* + * Emulate the single floating point instruction pointed at by EPC. + * Two instructions if the instruction is in a branch delay slot. + */ + +static int +cop1Emulate(int xcptno, struct pt_regs *xcp, + struct mips_fpu_soft_struct *ctx) +{ + mips_instruction ir; + vaddr_t emulpc; + vaddr_t contpc; + unsigned int cond; + int err = 0; + + + ir = mips_get_word(xcp, REG_TO_VA xcp->cp0_epc, &err); + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + + /* XXX NEC Vr54xx bug workaround */ + if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir)) + xcp->cp0_cause &= ~CAUSEF_BD; + + if (xcp->cp0_cause & CAUSEF_BD) { + /* + * The instruction to be emulated is in a branch delay slot + * which means that we have to emulate the branch instruction + * BEFORE we do the cop1 instruction. + * + * This branch could be a COP1 branch, but in that case we + * would have had a trap for that instruction, and would not + * come through this route. + * + * Linux MIPS branch emulator operates on context, updating the + * cp0_epc. + */ + emulpc = REG_TO_VA(xcp->cp0_epc + 4); /* Snapshot emulation target */ + + if (__compute_return_epc(xcp)) { +#ifdef CP1DBG + printk("failed to emulate branch at %p\n", + REG_TO_VA(xcp->cp0_epc)); +#endif + return SIGILL;; + } + ir = mips_get_word(xcp, emulpc, &err); + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + contpc = REG_TO_VA xcp->cp0_epc; + } else { + emulpc = REG_TO_VA xcp->cp0_epc; + contpc = REG_TO_VA xcp->cp0_epc + 4; + } + + emul: + fpuemuprivate.stats.emulated++; + switch (MIPSInst_OPCODE(ir)) { +#ifdef CP0_STATUS_FR_SUPPORT + /* R4000+ 64-bit fpu registers */ +#ifndef SINGLE_ONLY_FPU + case ldc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + int ft = MIPSInst_RT(ir); + if (!(xcp->cp0_status & ST0_FR)) + ft &= ~1; + ctx->regs[ft] = mips_get_dword(xcp, va, &err); + fpuemuprivate.stats.loads++; + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; + + case sdc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + int ft = MIPSInst_RT(ir); + if (!(xcp->cp0_status & ST0_FR)) + ft &= ~1; + fpuemuprivate.stats.stores++; + if (mips_put_dword(xcp, va, ctx->regs[ft])) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; +#endif + + case lwc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + fpureg_t val; + int ft = MIPSInst_RT(ir); + fpuemuprivate.stats.loads++; + val = mips_get_word(xcp, va, &err); + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + if (xcp->cp0_status & ST0_FR) { + /* load whole register */ + ctx->regs[ft] = val; + } else if (ft & 1) { + /* load to m.s. 32 bits */ +#ifdef SINGLE_ONLY_FPU + /* illegal register in single-float mode */ + return SIGILL; +#else + ctx->regs[(ft & ~1)] &= 0xffffffff; + ctx->regs[(ft & ~1)] |= val << 32; +#endif + } else { + /* load to l.s. 32 bits */ + ctx->regs[ft] &= ~0xffffffffLL; + ctx->regs[ft] |= val; + } + } + break; + + case swc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + unsigned int val; + int ft = MIPSInst_RT(ir); + fpuemuprivate.stats.stores++; + if (xcp->cp0_status & ST0_FR) { + /* store whole register */ + val = ctx->regs[ft]; + } else if (ft & 1) { +#ifdef SINGLE_ONLY_FPU + /* illegal register in single-float mode */ + return SIGILL; +#else + /* store from m.s. 32 bits */ + val = ctx->regs[(ft & ~1)] >> 32; +#endif + } else { + /* store from l.s. 32 bits */ + val = ctx->regs[ft]; + } + if (mips_put_word(xcp, va, val)) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; +#else /* old 32-bit fpu registers */ + case lwc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + ctx->regs[MIPSInst_RT(ir)] = + mips_get_word(xcp, va, &err); + fpuemuprivate.stats.loads++; + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; + + case swc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + fpuemuprivate.stats.stores++; + if (mips_put_word + (xcp, va, ctx->regs[MIPSInst_RT(ir)])) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + } + break; + case ldc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + unsigned int rt = MIPSInst_RT(ir) & ~1; + int errs = 0; + fpuemuprivate.stats.loads++; +#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) + ctx->regs[rt + 1] = + mips_get_word(xcp, va + 0, &err); + errs += err; + ctx->regs[rt + 0] = + mips_get_word(xcp, va + 4, &err); + errs += err; +#else + ctx->regs[rt + 0] = + mips_get_word(xcp, va + 0, &err); + errs += err; + ctx->regs[rt + 1] = + mips_get_word(xcp, va + 4, &err); + errs += err; +#endif + if (err) + return SIGBUS; + } + break; + + case sdc1_op: + { + void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)]) + + MIPSInst_SIMM(ir); + unsigned int rt = MIPSInst_RT(ir) & ~1; + fpuemuprivate.stats.stores++; +#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) + if (mips_put_word(xcp, va + 0, ctx->regs[rt + 1])) + return SIGBUS; + if (mips_put_word(xcp, va + 4, ctx->regs[rt + 0])) + return SIGBUS; +#else + if (mips_put_word(xcp, va + 0, ctx->regs[rt + 0])) + return SIGBUS; + if (mips_put_word(xcp, va + 4, ctx->regs[rt + 1])) + return SIGBUS; +#endif + } + break; +#endif + + case cop1_op: + switch (MIPSInst_RS(ir)) { + +#ifdef CP0_STATUS_FR_SUPPORT +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case dmfc_op: + /* copregister fs -> gpr[rt] */ + if (MIPSInst_RT(ir) != 0) { + int fs = MIPSInst_RD(ir); + if (!(xcp->cp0_status & ST0_FR)) + fs &= ~1; + xcp->regs[MIPSInst_RT(ir)] = ctx->regs[fs]; + } + break; + + case dmtc_op: + /* copregister fs <- rt */ + { + fpureg_t value; + int fs = MIPSInst_RD(ir); + if (!(xcp->cp0_status & ST0_FR)) + fs &= ~1; + value = + (MIPSInst_RT(ir) == + 0) ? 0 : xcp->regs[MIPSInst_RT(ir)]; + ctx->regs[fs] = value; + } + break; +#endif + + case mfc_op: + /* copregister rd -> gpr[rt] */ + if (MIPSInst_RT(ir) != 0) { + /* default value from l.s. 32 bits */ + int value = ctx->regs[MIPSInst_RD(ir)]; + if (MIPSInst_RD(ir) & 1) { +#ifdef SINGLE_ONLY_FPU + /* illegal register in single-float mode */ + return SIGILL; +#else + if (!(xcp->cp0_status & ST0_FR)) { + /* move from m.s. 32 bits */ + value = + ctx-> + regs[MIPSInst_RD(ir) & + ~1] >> 32; + } +#endif + } + xcp->regs[MIPSInst_RT(ir)] = value; + } + break; + + case mtc_op: + /* copregister rd <- rt */ + { + fpureg_t value; + if (MIPSInst_RT(ir) == 0) + value = 0; + else + value = + (unsigned int) xcp-> + regs[MIPSInst_RT(ir)]; + if (MIPSInst_RD(ir) & 1) { +#ifdef SINGLE_ONLY_FPU + /* illegal register in single-float mode */ + return SIGILL; +#else + if (!(xcp->cp0_status & ST0_FR)) { + /* move to m.s. 32 bits */ + ctx-> + regs[ + (MIPSInst_RD(ir) & + ~1)] &= + 0xffffffff; + ctx-> + regs[ + (MIPSInst_RD(ir) & + ~1)] |= + value << 32; + break; + } +#endif + } + /* move to l.s. 32 bits */ + ctx->regs[MIPSInst_RD(ir)] &= + ~0xffffffffLL; + ctx->regs[MIPSInst_RD(ir)] |= value; + } + break; +#else + + case mfc_op: + /* copregister rd -> gpr[rt] */ + if (MIPSInst_RT(ir) != 0) { + unsigned value = + ctx->regs[MIPSInst_RD(ir)]; + xcp->regs[MIPSInst_RT(ir)] = value; + } + break; + + case mtc_op: + /* copregister rd <- rt */ + { + unsigned value; + value = + (MIPSInst_RT(ir) == + 0) ? 0 : xcp->regs[MIPSInst_RT(ir)]; + ctx->regs[MIPSInst_RD(ir)] = value; + } + break; +#endif + + case cfc_op: + /* cop control register rd -> gpr[rt] */ + { + unsigned value; + + if (MIPSInst_RD(ir) == FPCREG_CSR) { + value = ctx->sr; +#ifdef CSRTRACE + printk + ("%p gpr[%d]<-csr=%08x\n", + REG_TO_VA(xcp->cp0_epc), + MIPSInst_RT(ir), value); +#endif + } else if (MIPSInst_RD(ir) == FPCREG_RID) + value = 0; + else + value = 0; + if (MIPSInst_RT(ir)) + xcp->regs[MIPSInst_RT(ir)] = value; + } + break; + + case ctc_op: + /* copregister rd <- rt */ + { + unsigned value; + + if (MIPSInst_RT(ir) == 0) + value = 0; + else + value = xcp->regs[MIPSInst_RT(ir)]; + + /* we only have one writable control reg + */ + if (MIPSInst_RD(ir) == FPCREG_CSR) { +#ifdef CSRTRACE + printk + ("%p gpr[%d]->csr=%08x\n", + REG_TO_VA(xcp->cp0_epc), + MIPSInst_RT(ir), value); +#endif + ctx->sr = value; + /* copy new rounding mode to ieee library state! */ + ieee754_csr.rm = + ieee_rm[value & 0x3]; + } + } + break; + + case bc_op: + if (xcp->cp0_cause & CAUSEF_BD) { + return SIGILL; + } + { + int likely = 0; + +#if __mips >= 4 + cond = + ctx-> + sr & fpucondbit[MIPSInst_RT(ir) >> 2]; +#else + cond = ctx->sr & FPU_CSR_COND; +#endif + switch (MIPSInst_RT(ir) & 3) { + case bcfl_op: + likely = 1; + case bcf_op: + cond = !cond; + break; + case bctl_op: + likely = 1; + case bct_op: + break; + default: + /* thats an illegal instruction */ + return SIGILL; + } + + xcp->cp0_cause |= CAUSEF_BD; + if (cond) { + /* branch taken: emulate dslot instruction */ + xcp->cp0_epc += 4; + contpc = + REG_TO_VA xcp->cp0_epc + + (MIPSInst_SIMM(ir) << 2); + + ir = + mips_get_word(xcp, + REG_TO_VA(xcp-> + cp0_epc), + &err); + if (err) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + + switch (MIPSInst_OPCODE(ir)) { + case lwc1_op: + case swc1_op: +#if (__mips >= 2 || __mips64) && !defined(SINGLE_ONLY_FPU) + case ldc1_op: + case sdc1_op: +#endif + case cop1_op: +#if __mips >= 4 && __mips != 32 + case cop1x_op: +#endif + /* its one of ours */ + goto emul; +#if __mips >= 4 + case spec_op: + if (MIPSInst_FUNC(ir) == + movc_op) goto emul; + break; +#endif + } + + /* single step the non-cp1 instruction in the dslot */ + return mips_dsemul(xcp, ir, contpc); + } else { + /* branch not taken */ + if (likely) + /* branch likely nullifies dslot if not taken */ + xcp->cp0_epc += 4; + /* else continue & execute dslot as normal insn */ + } + } + break; + + default: + if (!(MIPSInst_RS(ir) & 0x10)) { + return SIGILL; + } + /* a real fpu computation instruction */ + { + int sig; + if ((sig = fpu_emu(xcp, ctx, ir))) + return sig; + } + } + break; + +#if __mips >= 4 && __mips != 32 + case cop1x_op: + { + int sig; + if ((sig = fpux_emu(xcp, ctx, ir))) + return sig; + } + break; +#endif + +#if __mips >= 4 + case spec_op: + if (MIPSInst_FUNC(ir) != movc_op) + return SIGILL; + cond = fpucondbit[MIPSInst_RT(ir) >> 2]; + if (((ctx->sr & cond) != 0) != + ((MIPSInst_RT(ir) & 1) != 0)) return 0; + xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)]; + break; +#endif + + default: + return SIGILL; + } + + /* we did it !! */ + xcp->cp0_epc = VA_TO_REG(contpc); + xcp->cp0_cause &= ~CAUSEF_BD; + return 0; +} + +/* + * Emulate the arbritrary instruction ir at xcp->cp0_epc. Required when + * we have to emulate the instruction in a COP1 branch delay slot. Do + * not change cp0_epc due to the instruction + * + * According to the spec: + * 1) it shouldnt be a branch :-) + * 2) it can be a COP instruction :-( + * 3) if we are tring to run a protected memory space we must take + * special care on memory access instructions :-( + */ + +/* + * "Trampoline" return routine to catch exception following + * execution of delay-slot instruction execution. + */ + +int do_dsemulret(struct pt_regs *xcp) +{ +#ifdef DSEMUL_TRACE + printk("desemulret\n"); +#endif + /* Set EPC to return to post-branch instruction */ + xcp->cp0_epc = current->thread.dsemul_epc; + /* + * Clear the state that got us here. + */ + current->thread.dsemul_aerpc = (unsigned long) 0; + + return 0; +} + + +#define AdELOAD 0x8c000001 /* lw $0,1($0) */ + +static int +mips_dsemul(struct pt_regs *xcp, mips_instruction ir, vaddr_t cpc) +{ + mips_instruction *dsemul_insns; + mips_instruction forcetrap; + extern asmlinkage void handle_dsemulret(void); + + if (ir == 0) { /* a nop is easy */ + xcp->cp0_epc = VA_TO_REG(cpc); + return 0; + } +#ifdef DSEMUL_TRACE + printk("desemul %p %p\n", REG_TO_VA(xcp->cp0_epc), cpc); +#endif + + /* + * The strategy is to push the instruction onto the user stack + * and put a trap after it which we can catch and jump to + * the required address any alternative apart from full + * instruction emulation!!. + */ + dsemul_insns = (mips_instruction *) (xcp->regs[29] & ~3); + dsemul_insns -= 3; /* Two instructions, plus one for luck ;-) */ + /* Verify that the stack pointer is not competely insane */ + if (verify_area + (VERIFY_WRITE, dsemul_insns, sizeof(mips_instruction) * 2)) + return SIGBUS; + + if (mips_put_word(xcp, &dsemul_insns[0], ir)) { + fpuemuprivate.stats.errors++; + return (SIGBUS); + } + + /* + * Algorithmics used a system call instruction, and + * borrowed that vector. MIPS/Linux version is a bit + * more heavyweight in the interests of portability and + * multiprocessor support. We flag the thread for special + * handling in the unaligned access handler and force an + * address error excpetion. + */ + + /* If one is *really* paranoid, one tests for a bad stack pointer */ + if ((xcp->regs[29] & 0x3) == 0x3) + forcetrap = AdELOAD - 1; + else + forcetrap = AdELOAD; + + if (mips_put_word(xcp, &dsemul_insns[1], forcetrap)) { + fpuemuprivate.stats.errors++; + return (SIGBUS); + } + + /* Set thread state to catch and handle the exception */ + current->thread.dsemul_epc = (unsigned long) cpc; + current->thread.dsemul_aerpc = (unsigned long) &dsemul_insns[1]; + xcp->cp0_epc = VA_TO_REG & dsemul_insns[0]; + + /* What we'd really like to do is just flush the line(s) of the */ + /* icache containing the dsemulret instructions, but there's no */ + /* mechanism to do this yet... */ + flush_cache_all(); + return SIGILL; /* force out of emulation loop */ +} + +/* + * Conversion table from MIPS compare ops 48-63 + * cond = ieee754dp_cmp(x,y,IEEE754_UN); + */ +static const unsigned char cmptab[8] = { + 0, /* cmp_0 (sig) cmp_sf */ + IEEE754_CUN, /* cmp_un (sig) cmp_ngle */ + IEEE754_CEQ, /* cmp_eq (sig) cmp_seq */ + IEEE754_CEQ | IEEE754_CUN, /* cmp_ueq (sig) cmp_ngl */ + IEEE754_CLT, /* cmp_olt (sig) cmp_lt */ + IEEE754_CLT | IEEE754_CUN, /* cmp_ult (sig) cmp_nge */ + IEEE754_CLT | IEEE754_CEQ, /* cmp_ole (sig) cmp_le */ + IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */ +}; + +#define SIFROMREG(si,x) ((si) = ctx->regs[x]) +#define SITOREG(si,x) (ctx->regs[x] = (int)(si)) + +#if __mips64 && !defined(SINGLE_ONLY_FPU) +#define DIFROMREG(di,x) ((di) = ctx->regs[x]) +#define DITOREG(di,x) (ctx->regs[x] = (di)) +#endif + +#define SPFROMREG(sp,x) ((sp).bits = ctx->regs[x]) +#define SPTOREG(sp,x) (ctx->regs[x] = (sp).bits) + +#ifdef CP0_STATUS_FR_SUPPORT +#define DPFROMREG(dp,x) ((dp).bits = \ + ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)]) +#define DPTOREG(dp,x) (ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)]\ + = (dp).bits) +#else +/* Beware: MIPS COP1 doubles are always little_word endian in registers */ +#define DPFROMREG(dp,x) \ + ((dp).bits = ((unsigned long long)ctx->regs[(x)+1] << 32) | ctx->regs[x]) +#define DPTOREG(dp,x) \ + (ctx->regs[x] = (dp).bits, ctx->regs[(x)+1] = (dp).bits >> 32) +#endif + +#if __mips >= 4 && __mips != 32 + +/* + * Additional MIPS4 instructions + */ + +static ieee754dp fpemu_dp_recip(ieee754dp d) +{ + return ieee754dp_div(ieee754dp_one(0), d); +} + +static ieee754dp fpemu_dp_rsqrt(ieee754dp d) +{ + return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d)); +} + +static ieee754sp fpemu_sp_recip(ieee754sp s) +{ + return ieee754sp_div(ieee754sp_one(0), s); +} + +static ieee754sp fpemu_sp_rsqrt(ieee754sp s) +{ + return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s)); +} + + +static ieee754dp fpemu_dp_madd(ieee754dp r, ieee754dp s, ieee754dp t) +{ + return ieee754dp_add(ieee754dp_mul(s, t), r); +} + +static ieee754dp fpemu_dp_msub(ieee754dp r, ieee754dp s, ieee754dp t) +{ + return ieee754dp_sub(ieee754dp_mul(s, t), r); +} + +static ieee754dp fpemu_dp_nmadd(ieee754dp r, ieee754dp s, ieee754dp t) +{ + return ieee754dp_neg(ieee754dp_add(ieee754dp_mul(s, t), r)); +} + +static ieee754dp fpemu_dp_nmsub(ieee754dp r, ieee754dp s, ieee754dp t) +{ + return ieee754dp_neg(ieee754dp_sub(ieee754dp_mul(s, t), r)); +} + + +static ieee754sp fpemu_sp_madd(ieee754sp r, ieee754sp s, ieee754sp t) +{ + return ieee754sp_add(ieee754sp_mul(s, t), r); +} + +static ieee754sp fpemu_sp_msub(ieee754sp r, ieee754sp s, ieee754sp t) +{ + return ieee754sp_sub(ieee754sp_mul(s, t), r); +} + +static ieee754sp fpemu_sp_nmadd(ieee754sp r, ieee754sp s, ieee754sp t) +{ + return ieee754sp_neg(ieee754sp_add(ieee754sp_mul(s, t), r)); +} + +static ieee754sp fpemu_sp_nmsub(ieee754sp r, ieee754sp s, ieee754sp t) +{ + return ieee754sp_neg(ieee754sp_sub(ieee754sp_mul(s, t), r)); +} + +static int +fpux_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx, + mips_instruction ir) +{ + unsigned rcsr = 0; /* resulting csr */ + + fpuemuprivate.stats.cp1xops++; + + switch (MIPSInst_FMA_FFMT(ir)) { + case s_fmt: /* 0 */ + { + ieee754sp(*handler) (ieee754sp, ieee754sp, + ieee754sp); + ieee754sp fd, fr, fs, ft; + + switch (MIPSInst_FUNC(ir)) { + case lwxc1_op: + { + void *va = + REG_TO_VA(xcp-> + regs[MIPSInst_FR(ir)] + + + xcp-> + regs[MIPSInst_FT + (ir)]); + fpureg_t val; + int err = 0; + val = mips_get_word(xcp, va, &err); + if (err) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + if (xcp->cp0_status & ST0_FR) { + /* load whole register */ + ctx-> + regs[MIPSInst_FD(ir)] = + val; + } else if (MIPSInst_FD(ir) & 1) { + /* load to m.s. 32 bits */ +#if defined(SINGLE_ONLY_FPU) + /* illegal register in single-float mode */ + return SIGILL; +#else + ctx-> + regs[ + (MIPSInst_FD(ir) & + ~1)] &= + 0xffffffff; + ctx-> + regs[ + (MIPSInst_FD(ir) & + ~1)] |= + val << 32; +#endif + } else { + /* load to l.s. 32 bits */ + ctx-> + regs[MIPSInst_FD(ir)] + &= ~0xffffffffLL; + ctx-> + regs[MIPSInst_FD(ir)] + |= val; + } + } + break; + + case swxc1_op: + { + void *va = + REG_TO_VA(xcp-> + regs[MIPSInst_FR(ir)] + + + xcp-> + regs[MIPSInst_FT + (ir)]); + unsigned int val; + if (xcp->cp0_status & ST0_FR) { + /* store whole register */ + val = + ctx-> + regs[MIPSInst_FS(ir)]; + } else if (MIPSInst_FS(ir) & 1) { +#if defined(SINGLE_ONLY_FPU) + /* illegal register in single-float mode */ + return SIGILL; +#else + /* store from m.s. 32 bits */ + val = + ctx-> + regs[ + (MIPSInst_FS(ir) & + ~1)] >> 32; +#endif + } else { + /* store from l.s. 32 bits */ + val = + ctx-> + regs[MIPSInst_FS(ir)]; + } + if (mips_put_word(xcp, va, val)) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + } + break; + + case madd_s_op: + handler = fpemu_sp_madd; + goto scoptop; + case msub_s_op: + handler = fpemu_sp_msub; + goto scoptop; + case nmadd_s_op: + handler = fpemu_sp_nmadd; + goto scoptop; + case nmsub_s_op: + handler = fpemu_sp_nmsub; + goto scoptop; + + scoptop: + SPFROMREG(fr, MIPSInst_FR(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(ft, MIPSInst_FT(ir)); + fd = (*handler) (fr, fs, ft); + SPTOREG(fd, MIPSInst_FD(ir)); + + copcsr: + if (ieee754_cxtest(IEEE754_INEXACT)) + rcsr |= + FPU_CSR_INE_X | FPU_CSR_INE_S; + if (ieee754_cxtest(IEEE754_UNDERFLOW)) + rcsr |= + FPU_CSR_UDF_X | FPU_CSR_UDF_S; + if (ieee754_cxtest(IEEE754_OVERFLOW)) + rcsr |= + FPU_CSR_OVF_X | FPU_CSR_OVF_S; + if (ieee754_cxtest + (IEEE754_INVALID_OPERATION)) rcsr |= + FPU_CSR_INV_X | FPU_CSR_INV_S; + + ctx->sr = + (ctx->sr & ~FPU_CSR_ALL_X) | rcsr; + if ((ctx->sr >> 5) & ctx-> + sr & FPU_CSR_ALL_E) { + /*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */ + return SIGFPE; + } + + break; + + default: + return SIGILL; + } + } + break; + +#if !defined(SINGLE_ONLY_FPU) + case d_fmt: /* 1 */ + { + ieee754dp(*handler) (ieee754dp, ieee754dp, + ieee754dp); + ieee754dp fd, fr, fs, ft; + + switch (MIPSInst_FUNC(ir)) { + case ldxc1_op: + { + void *va = + REG_TO_VA(xcp-> + regs[MIPSInst_FR(ir)] + + + xcp-> + regs[MIPSInst_FT + (ir)]); + int err = 0; + ctx->regs[MIPSInst_FD(ir)] = + mips_get_dword(xcp, va, &err); + if (err) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + } + break; + + case sdxc1_op: + { + void *va = + REG_TO_VA(xcp-> + regs[MIPSInst_FR(ir)] + + + xcp-> + regs[MIPSInst_FT + (ir)]); + if (mips_put_dword + (xcp, va, + ctx->regs[MIPSInst_FS(ir)])) { + fpuemuprivate.stats. + errors++; + return SIGBUS; + } + } + break; + + case madd_d_op: + handler = fpemu_dp_madd; + goto dcoptop; + case msub_d_op: + handler = fpemu_dp_msub; + goto dcoptop; + case nmadd_d_op: + handler = fpemu_dp_nmadd; + goto dcoptop; + case nmsub_d_op: + handler = fpemu_dp_nmsub; + goto dcoptop; + + dcoptop: + DPFROMREG(fr, MIPSInst_FR(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(ft, MIPSInst_FT(ir)); + fd = (*handler) (fr, fs, ft); + DPTOREG(fd, MIPSInst_FD(ir)); + goto copcsr; + + default: + return SIGILL; + } + } + break; +#endif + + case 0x7: /* 7 */ + { + if (MIPSInst_FUNC(ir) != pfetch_op) { + return SIGILL; + } + /* ignore prefx operation */ + } + break; + + default: + return SIGILL; + } + + return 0; +} +#endif + + + +/* + * Emulate a single COP1 arithmetic instruction. + */ +static int +fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx, + mips_instruction ir) +{ + int rfmt; /* resulting format */ + unsigned rcsr = 0; /* resulting csr */ + unsigned cond; + union { + ieee754dp d; + ieee754sp s; + int w; +#if __mips64 + long long l; +#endif + } rv; /* resulting value */ + + fpuemuprivate.stats.cp1ops++; + switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { + + case s_fmt:{ /* 0 */ + ieee754sp(*handler) (); + + switch (MIPSInst_FUNC(ir)) { + /* binary ops */ + case fadd_op: + handler = ieee754sp_add; + goto scopbop; + case fsub_op: + handler = ieee754sp_sub; + goto scopbop; + case fmul_op: + handler = ieee754sp_mul; + goto scopbop; + case fdiv_op: + handler = ieee754sp_div; + goto scopbop; + + /* unary ops */ +#if __mips >= 2 || __mips64 + case fsqrt_op: + handler = ieee754sp_sqrt; + goto scopuop; +#endif +#if __mips >= 4 && __mips != 32 + case frsqrt_op: + handler = fpemu_sp_rsqrt; + goto scopuop; + case frecip_op: + handler = fpemu_sp_recip; + goto scopuop; +#endif +#if __mips >= 4 + case fmovc_op: + cond = fpucondbit[MIPSInst_FT(ir) >> 2]; + if (((ctx->sr & cond) != 0) != + ((MIPSInst_FT(ir) & 1) != 0)) + return 0; + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; + case fmovz_op: + if (xcp->regs[MIPSInst_FT(ir)] != 0) + return 0; + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; + case fmovn_op: + if (xcp->regs[MIPSInst_FT(ir)] == 0) + return 0; + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; +#endif + case fabs_op: + handler = ieee754sp_abs; + goto scopuop; + case fneg_op: + handler = ieee754sp_neg; + goto scopuop; + case fmov_op: + /* an easy one */ + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; + /* binary op on handler */ +scopbop: + { + ieee754sp fs, ft; + + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(ft, MIPSInst_FT(ir)); + + rv.s = (*handler) (fs, ft); + goto copcsr; + } +scopuop: + { + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = (*handler) (fs); + goto copcsr; + } +copcsr: + if (ieee754_cxtest(IEEE754_INEXACT)) + rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; + if (ieee754_cxtest(IEEE754_UNDERFLOW)) + rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; + if (ieee754_cxtest(IEEE754_OVERFLOW)) + rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; + if (ieee754_cxtest(IEEE754_ZERO_DIVIDE)) + rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S; + if (ieee754_cxtest + (IEEE754_INVALID_OPERATION)) rcsr |= + FPU_CSR_INV_X | FPU_CSR_INV_S; + break; + + /* unary conv ops */ + case fcvts_op: + return SIGILL; /* not defined */ + case fcvtd_op: +#if defined(SINGLE_ONLY_FPU) + return SIGILL; /* not defined */ +#else + { + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = ieee754dp_fsp(fs); + rfmt = d_fmt; + goto copcsr; + } +#endif + case fcvtw_op: + { + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.w = ieee754sp_tint(fs); + rfmt = w_fmt; + goto copcsr; + } + +#if __mips >= 2 || __mips64 + case fround_op: + case ftrunc_op: + case fceil_op: + case ffloor_op: + { + unsigned int oldrm = ieee754_csr.rm; + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; + rv.w = ieee754sp_tint(fs); + ieee754_csr.rm = oldrm; + rfmt = w_fmt; + goto copcsr; + } +#endif /* __mips >= 2 */ + +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case fcvtl_op: + { + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.l = ieee754sp_tlong(fs); + rfmt = l_fmt; + goto copcsr; + } + + case froundl_op: + case ftruncl_op: + case fceill_op: + case ffloorl_op: + { + unsigned int oldrm = ieee754_csr.rm; + ieee754sp fs; + + SPFROMREG(fs, MIPSInst_FS(ir)); + ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; + rv.l = ieee754sp_tlong(fs); + ieee754_csr.rm = oldrm; + rfmt = l_fmt; + goto copcsr; + } +#endif /* __mips64 && !fpu(single) */ + + default: + if (MIPSInst_FUNC(ir) >= fcmp_op) { + unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; + ieee754sp fs, ft; + + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(ft, MIPSInst_FT(ir)); + rv.w = ieee754sp_cmp(fs, ft, cmptab[cmpop & 0x7]); + rfmt = -1; + if ((cmpop & 0x8) && ieee754_cxtest(IEEE754_INVALID_OPERATION)) + rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + } else { + return SIGILL; + } + break; + } + break; + } + +#if !defined(SINGLE_ONLY_FPU) + case d_fmt: { + ieee754dp(*handler) (); + + switch (MIPSInst_FUNC(ir)) { + /* binary ops */ + case fadd_op: + handler = ieee754dp_add; + goto dcopbop; + case fsub_op: + handler = ieee754dp_sub; + goto dcopbop; + case fmul_op: + handler = ieee754dp_mul; + goto dcopbop; + case fdiv_op: + handler = ieee754dp_div; + goto dcopbop; + + /* unary ops */ +#if __mips >= 2 || __mips64 + case fsqrt_op: + handler = ieee754dp_sqrt; + goto dcopuop; +#endif +#if __mips >= 4 && __mips != 32 + case frsqrt_op: + handler = fpemu_dp_rsqrt; + goto dcopuop; + case frecip_op: + handler = fpemu_dp_recip; + goto dcopuop; +#endif +#if __mips >= 4 + case fmovc_op: + cond = fpucondbit[MIPSInst_FT(ir) >> 2]; + if (((ctx->sr & cond) != 0) != ((MIPSInst_FT(ir) & 1) != 0)) + return 0; + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; + case fmovz_op: + if (xcp->regs[MIPSInst_FT(ir)] != 0) + return 0; + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; + case fmovn_op: + if (xcp->regs[MIPSInst_FT(ir)] == 0) + return 0; + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; +#endif + case fabs_op: + handler = ieee754dp_abs; + goto dcopuop; + case fneg_op: + handler = ieee754dp_neg; + goto dcopuop; + case fmov_op: + /* an easy one */ + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; + + /* binary op on handler */ +dcopbop: + { + ieee754dp fs, ft; + + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(ft, MIPSInst_FT(ir)); + + rv.d = (*handler) (fs, ft); + goto copcsr; + } +dcopuop: + { + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = (*handler) (fs); + goto copcsr; + } + + /* unary conv ops */ + case fcvts_op: + { + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = ieee754sp_fdp(fs); + rfmt = s_fmt; + goto copcsr; + } + case fcvtd_op: + return SIGILL; /* not defined */ + case fcvtw_op: + { + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.w = ieee754dp_tint(fs); /* wrong */ + rfmt = w_fmt; + goto copcsr; + } + +#if __mips >= 2 || __mips64 + case fround_op: + case ftrunc_op: + case fceil_op: + case ffloor_op: + { + unsigned int oldrm = ieee754_csr.rm; + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; + rv.w = ieee754dp_tint(fs); + ieee754_csr.rm = oldrm; + rfmt = w_fmt; + goto copcsr; + } +#endif + +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case fcvtl_op: + { + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.l = ieee754dp_tlong(fs); + rfmt = l_fmt; + goto copcsr; + } + + case froundl_op: + case ftruncl_op: + case fceill_op: + case ffloorl_op: + { + unsigned int oldrm = ieee754_csr.rm; + ieee754dp fs; + + DPFROMREG(fs, MIPSInst_FS(ir)); + ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; + rv.l = ieee754dp_tlong(fs); + ieee754_csr.rm = oldrm; + rfmt = l_fmt; + goto copcsr; + } +#endif /* __mips >= 3 && !fpu(single) */ + + default: + if (MIPSInst_FUNC(ir) >= fcmp_op) { + unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; + ieee754dp fs, ft; + + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(ft, MIPSInst_FT(ir)); + rv.w = ieee754dp_cmp(fs, ft, cmptab[cmpop & 0x7]); + rfmt = -1; + if ((cmpop & 0x8) && ieee754_cxtest (IEEE754_INVALID_OPERATION)) + rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + } else { + return SIGILL; + } + break; + } + break; + } +#endif /* !defined(SINGLE_ONLY_FPU) */ + + case w_fmt: { + switch (MIPSInst_FUNC(ir)) { + case fcvts_op: + /* convert word to single precision real */ + rv.s = ieee754sp_fint(ctx-> regs[MIPSInst_FS(ir)]); + rfmt = s_fmt; + goto copcsr; +#if !defined(SINGLE_ONLY_FPU) + case fcvtd_op: + /* convert word to double precision real */ + rv.d = ieee754dp_fint(ctx-> regs[MIPSInst_FS(ir)]); + rfmt = d_fmt; + goto copcsr; +#endif + default: + return SIGILL; + } + break; + } + +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case l_fmt: { + switch (MIPSInst_FUNC(ir)) { + case fcvts_op: + /* convert long to single precision real */ + rv.s = ieee754sp_flong(ctx-> regs[MIPSInst_FS(ir)]); + rfmt = s_fmt; + goto copcsr; + case fcvtd_op: + /* convert long to double precision real */ + rv.d = ieee754dp_flong(ctx-> regs[MIPSInst_FS(ir)]); + rfmt = d_fmt; + goto copcsr; + default: + return SIGILL; + } + break; + } +#endif + + default: + return SIGILL; + } + + /* + * Update the fpu CSR register for this operation. + * If an exception is required, generate a tidy SIGFPE exception, + * without updating the result register. + * Note: cause exception bits do not accumulate, they are rewritten + * for each op; only the flag/sticky bits accumulate. + */ + ctx->sr = (ctx->sr & ~FPU_CSR_ALL_X) | rcsr; + if ((ctx->sr >> 5) & ctx->sr & FPU_CSR_ALL_E) { + /*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */ + return SIGFPE; + } + + /* + * Now we can safely write the result back to the register file. + */ + switch (rfmt) { + case -1: { +#if __mips >= 4 + cond = fpucondbit[MIPSInst_FD(ir) >> 2]; +#else + cond = FPU_CSR_COND; +#endif + if (rv.w) + ctx->sr |= cond; + else + ctx->sr &= ~cond; + break; + } +#if !defined(SINGLE_ONLY_FPU) + case d_fmt: + DPTOREG(rv.d, MIPSInst_FD(ir)); + break; +#endif + case s_fmt: + SPTOREG(rv.s, MIPSInst_FD(ir)); + break; + case w_fmt: + SITOREG(rv.w, MIPSInst_FD(ir)); + break; +#if __mips64 && !defined(SINGLE_ONLY_FPU) + case l_fmt: + DITOREG(rv.l, MIPSInst_FD(ir)); + break; +#endif + default: + return SIGILL; + } + + return 0; +} + + +/* + * Emulate the floating point instruction at EPC, and continue + * to run until we hit a non-fp instruction, or a backward + * branch. This cuts down dramatically on the per instruction + * exception overhead. + */ +int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp) +{ + struct mips_fpu_soft_struct *ctx = ¤t->thread.fpu.soft; + unsigned long oldepc, prevepc; + unsigned int insn; + int sig = 0; + int err = 0; + + oldepc = xcp->cp0_epc; + do { + prevepc = xcp->cp0_epc; + insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err); + if (err) { + fpuemuprivate.stats.errors++; + return SIGBUS; + } + if (insn != 0) + sig = cop1Emulate(xcptno, xcp, ctx); + else + xcp->cp0_epc += 4; /* skip nops */ + } while (xcp->cp0_epc > prevepc && sig == 0); + + /* SIGILL indicates a non-fpu instruction */ + if (sig == SIGILL && xcp->cp0_epc != oldepc) + /* but if epc has advanced, then ignore it */ + sig = 0; + + return sig; +} + + +#ifdef NOTDEF +/* + * Patch up the hardware fpu state when an f.p. exception occurs. + */ +static int cop1Patcher(int xcptno, struct pt_regs *xcp) +{ + struct mips_fpu_soft_struct *ctx = ¤t->thread.fpu.soft; + unsigned sr; + int sig; + + /* reenable Cp1, else fpe_save() will get nested exception */ + sr = mips_bissr(ST0_CU1); + + /* get fpu registers and status, then clear pending exceptions */ + fpe_save(ctx); + fpe_setsr(ctx->sr &= ~FPU_CSR_ALL_X); + + /* get current rounding mode for IEEE library, and emulate insn */ + ieee754_csr.rm = ieee_rm[ctx->sr & 0x3]; + sig = cop1Emulate(xcptno, xcp, ctx); + + /* don't return with f.p. exceptions pending */ + ctx->sr &= ~FPU_CSR_ALL_X; + fpe_restore(ctx); + + mips_setsr(sr); + return sig; +} + +void _cop1_init(int emulate) +{ + extern int _nofpu; + + if (emulate) { + /* + * Install cop1 emulator to handle "coprocessor unusable" exception + */ + xcption(XCPTCPU, cop1Handler); + fpuemuactive = 1; /* tell dbg.c that we are in charge */ + _nofpu = 0; /* tell setjmp() it "has" an fpu */ + } else { + /* + * Install cop1 emulator for floating point exceptions only, + * i.e. denormalised results, underflow, overflow etc, which + * must be emulated in s/w. + */ +#ifdef 1 + /* r4000 or above use dedicate exception */ + xcption(XCPTFPE, cop1Patcher); +#else + /* r3000 et al use interrupt */ + extern int _sbd_getfpuintr(void); + int intno = _sbd_getfpuintr(); + intrupt(intno, cop1Patcher, 0); + mips_bissr(SR_IM0 << intno); +#endif + +#if (#cpu(r4640) || #cpu(r4650)) && !defined(SINGLE_ONLY_FPU) + /* For R4640/R4650 compiled *without* the -msingle-float flag, + then we share responsibility: the h/w handles the single + precision operations, and the trap emulator handles the + double precision. We set fpuemuactive so that dbg.c first + fetches the s/w state before saving the h/w state. */ + fpuemuactive = 1; + { + int i; + /* initialise the unused d.p high order words to be NaN */ + for (i = 0; i < 32; i++) + current->thread.fpu.soft.regs[i] = + 0x7ff80bad00000000LL; + } +#endif /* (r4640 || r4650) && !fpu(single) */ + } +} +#endif + diff --git a/arch/mips64/math-emu/dp_add.c b/arch/mips64/math-emu/dp_add.c new file mode 100644 index 000000000000..5a3158bbbc26 --- /dev/null +++ b/arch/mips64/math-emu/dp_add.c @@ -0,0 +1,186 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) +{ + COMPXDP; + COMPYDP; + + EXPLODEXDP; + EXPLODEYDP; + + CLEARCX; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "add", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y, "add", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x, "add", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754dp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Inifity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (xs == ys) + return x; + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "add", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + return y; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return x; + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + else + return ieee754dp_zero(ieee754_csr.rm == + IEEE754_RD); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return y; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + /* FALL THROUGH */ + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + /* provide guard,round and stick bit space */ + xm <<= 3; + ym <<= 3; + + if (xe > ye) { + /* have to shift y fraction right to align + */ + int s = xe - ye; + ym = XDPSRS(ym, s); + ye += s; + } else if (ye > xe) { + /* have to shift x fraction right to align + */ + int s = ye - xe; + xm = XDPSRS(xm, s); + xe += s; + } + assert(xe == ye); + assert(xe <= DP_EMAX); + + if (xs == ys) { + /* generate 28 bit result of adding two 27 bit numbers + * leaving result in xm,xs,xe + */ + xm = xm + ym; + xe = xe; + xs = xs; + + if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */ + xm = XDPSRS1(xm); + xe++; + } + } else { + if (xm >= ym) { + xm = xm - ym; + xe = xe; + xs = xs; + } else { + xm = ym - xm; + xe = xe; + xs = ys; + } + if (xm == 0) + return ieee754dp_zero(ieee754_csr.rm == + IEEE754_RD); + + /* normalize to rounding precision */ + while ((xm >> (DP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + + } + DPNORMRET2(xs, xe, xm, "add", x, y); +} diff --git a/arch/mips64/math-emu/dp_cmp.c b/arch/mips64/math-emu/dp_cmp.c new file mode 100644 index 000000000000..34ec4a856ce9 --- /dev/null +++ b/arch/mips64/math-emu/dp_cmp.c @@ -0,0 +1,58 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp) +{ + CLEARCX; + + if (ieee754dp_isnan(x) || ieee754dp_isnan(y)) { + if (cmp & IEEE754_CUN) + return 1; + if (cmp & (IEEE754_CLT | IEEE754_CGT)) { + if (SETCX(IEEE754_INVALID_OPERATION)) + return ieee754si_xcpt(0, "fcmpf", x); + } + return 0; + } else { + long long int vx = x.bits; + long long int vy = y.bits; + + if (vx < 0) + vx = -vx ^ DP_SIGN_BIT; + if (vy < 0) + vy = -vy ^ DP_SIGN_BIT; + + if (vx < vy) + return (cmp & IEEE754_CLT) != 0; + else if (vx == vy) + return (cmp & IEEE754_CEQ) != 0; + else + return (cmp & IEEE754_CGT) != 0; + } +} diff --git a/arch/mips64/math-emu/dp_div.c b/arch/mips64/math-emu/dp_div.c new file mode 100644 index 000000000000..fea2a0c13db9 --- /dev/null +++ b/arch/mips64/math-emu/dp_div.c @@ -0,0 +1,160 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) +{ + COMPXDP; + COMPYDP; + + CLEARCX; + + EXPLODEXDP; + EXPLODEYDP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "div", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y, "div", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x, "div", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754dp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Infinity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + return ieee754dp_zero(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return ieee754dp_inf(xs ^ ys); + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + SETCX(IEEE754_ZERO_DIVIDE); + return ieee754dp_xcpt(ieee754dp_inf(xs ^ ys), "div", x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return ieee754dp_zero(xs == ys ? 0 : 1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + /* provide rounding space */ + xm <<= 3; + ym <<= 3; + + { + /* now the dirty work */ + + unsigned long long rm = 0; + int re = xe - ye; + unsigned long long bm; + + for (bm = DP_MBIT(DP_MBITS + 2); bm; bm >>= 1) { + if (xm >= ym) { + xm -= ym; + rm |= bm; + if (xm == 0) + break; + } + xm <<= 1; + } + rm <<= 1; + if (xm) + rm |= 1; /* have remainder, set sticky */ + + assert(rm); + + /* normalise rm to rounding precision ? + */ + while ((rm >> (DP_MBITS + 3)) == 0) { + rm <<= 1; + re--; + } + + DPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y); + } +} diff --git a/arch/mips64/math-emu/dp_fint.c b/arch/mips64/math-emu/dp_fint.c new file mode 100644 index 000000000000..6f7e8611bcf4 --- /dev/null +++ b/arch/mips64/math-emu/dp_fint.c @@ -0,0 +1,78 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_fint(int x) +{ + COMPXDP; + + CLEARCX; + + if (x == 0) + return ieee754dp_zero(0); + if (x == 1 || x == -1) + return ieee754dp_one(x < 0); + if (x == 10 || x == -10) + return ieee754dp_ten(x < 0); + + xs = (x < 0); + if (xs) { + if (x == (1 << 31)) + xm = ((unsigned) 1 << 31); /* max neg can't be safely negated */ + else + xm = -x; + } else { + xm = x; + } + +#if 1 + /* normalize - result can never be inexact or overflow */ + xe = DP_MBITS; + while ((xm >> DP_MBITS) == 0) { + xm <<= 1; + xe--; + } + return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); +#else + /* normalize */ + xe = DP_MBITS + 3; + while ((xm >> (DP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + DPNORMRET1(xs, xe, xm, "fint", x); +#endif +} + +ieee754dp ieee754dp_funs(unsigned int u) +{ + if ((int) u < 0) + return ieee754dp_add(ieee754dp_1e31(), + ieee754dp_fint(u & ~(1 << 31))); + return ieee754dp_fint(u); +} diff --git a/arch/mips64/math-emu/dp_flong.c b/arch/mips64/math-emu/dp_flong.c new file mode 100644 index 000000000000..7abf5ee30d27 --- /dev/null +++ b/arch/mips64/math-emu/dp_flong.c @@ -0,0 +1,76 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_flong(long long x) +{ + COMPXDP; + + CLEARCX; + + if (x == 0) + return ieee754dp_zero(0); + if (x == 1 || x == -1) + return ieee754dp_one(x < 0); + if (x == 10 || x == -10) + return ieee754dp_ten(x < 0); + + xs = (x < 0); + if (xs) { + if (x == (1ULL << 63)) + xm = (1ULL << 63); /* max neg can't be safely negated */ + else + xm = -x; + } else { + xm = x; + } + + /* normalize */ + xe = DP_MBITS + 3; + if (xm >> (DP_MBITS + 1 + 3)) { + /* shunt out overflow bits */ + while (xm >> (DP_MBITS + 1 + 3)) { + XDPSRSX1(); + } + } else { + /* normalize in grs extended double precision */ + while ((xm >> (DP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + DPNORMRET1(xs, xe, xm, "dp_flong", x); +} + +ieee754dp ieee754dp_fulong(unsigned long long u) +{ + if ((long long) u < 0) + return ieee754dp_add(ieee754dp_1e63(), + ieee754dp_flong(u & ~(1ULL << 63))); + return ieee754dp_flong(u); +} diff --git a/arch/mips64/math-emu/dp_frexp.c b/arch/mips64/math-emu/dp_frexp.c new file mode 100644 index 000000000000..db2ef8543236 --- /dev/null +++ b/arch/mips64/math-emu/dp_frexp.c @@ -0,0 +1,53 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +/* close to ieeep754dp_logb +*/ +ieee754dp ieee754dp_frexp(ieee754dp x, int *eptr) +{ + COMPXDP; + CLEARCX; + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + *eptr = 0; + return x; + case IEEE754_CLASS_DNORM: + DPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + *eptr = xe + 1; + return builddp(xs, -1 + DP_EBIAS, xm & ~DP_HIDDEN_BIT); +} diff --git a/arch/mips64/math-emu/dp_fsp.c b/arch/mips64/math-emu/dp_fsp.c new file mode 100644 index 000000000000..7749e11d4ad6 --- /dev/null +++ b/arch/mips64/math-emu/dp_fsp.c @@ -0,0 +1,70 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_fsp(ieee754sp x) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + return ieee754dp_nanxcpt(builddp(xs, + DP_EMAX + 1 + DP_EBIAS, + ((unsigned long long) xm + << (DP_MBITS - + SP_MBITS))), "fsp", + x); + case IEEE754_CLASS_INF: + return ieee754dp_inf(xs); + case IEEE754_CLASS_ZERO: + return ieee754dp_zero(xs); + case IEEE754_CLASS_DNORM: + /* normalize */ + while ((xm >> SP_MBITS) == 0) { + xm <<= 1; + xe--; + } + break; + case IEEE754_CLASS_NORM: + break; + } + + /* CANT possibly overflow,underflow, or need rounding + */ + + /* drop the hidden bit */ + xm &= ~SP_HIDDEN_BIT; + + return builddp(xs, xe + DP_EBIAS, + (unsigned long long) xm << (DP_MBITS - SP_MBITS)); +} diff --git a/arch/mips64/math-emu/dp_logb.c b/arch/mips64/math-emu/dp_logb.c new file mode 100644 index 000000000000..22aeb211508b --- /dev/null +++ b/arch/mips64/math-emu/dp_logb.c @@ -0,0 +1,54 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_logb(ieee754dp x) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + return ieee754dp_nanxcpt(x, "logb", x); + case IEEE754_CLASS_QNAN: + return x; + case IEEE754_CLASS_INF: + return ieee754dp_inf(0); + case IEEE754_CLASS_ZERO: + return ieee754dp_inf(1); + case IEEE754_CLASS_DNORM: + DPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + return ieee754dp_fint(xe); +} diff --git a/arch/mips64/math-emu/dp_modf.c b/arch/mips64/math-emu/dp_modf.c new file mode 100644 index 000000000000..6bf0f2f149a0 --- /dev/null +++ b/arch/mips64/math-emu/dp_modf.c @@ -0,0 +1,80 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +/* modf function is always exact for a finite number +*/ +ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + *ip = x; + return x; + case IEEE754_CLASS_DNORM: + /* far to small */ + *ip = ieee754dp_zero(xs); + return x; + case IEEE754_CLASS_NORM: + break; + } + if (xe < 0) { + *ip = ieee754dp_zero(xs); + return x; + } + if (xe >= DP_MBITS) { + *ip = x; + return ieee754dp_zero(xs); + } + /* generate ipart mantissa by clearing bottom bits + */ + *ip = builddp(xs, xe + DP_EBIAS, + ((xm >> (DP_MBITS - xe)) << (DP_MBITS - xe)) & + ~DP_HIDDEN_BIT); + + /* generate fpart mantissa by clearing top bits + * and normalizing (must be able to normalize) + */ + xm = (xm << (64 - (DP_MBITS - xe))) >> (64 - (DP_MBITS - xe)); + if (xm == 0) + return ieee754dp_zero(xs); + + while ((xm >> DP_MBITS) == 0) { + xm <<= 1; + xe--; + } + return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); +} diff --git a/arch/mips64/math-emu/dp_mul.c b/arch/mips64/math-emu/dp_mul.c new file mode 100644 index 000000000000..9ec5d40605c7 --- /dev/null +++ b/arch/mips64/math-emu/dp_mul.c @@ -0,0 +1,180 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) +{ + COMPXDP; + COMPYDP; + + CLEARCX; + + EXPLODEXDP; + EXPLODEYDP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "mul", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y, "mul", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x, "mul", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754dp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Infinity handeling */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "mul", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + return ieee754dp_inf(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return ieee754dp_zero(xs ^ ys); + + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + /* rm = xm * ym, re = xe+ye basicly */ + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + { + int re = xe + ye; + int rs = xs ^ ys; + unsigned long long rm; + + /* shunt to top of word */ + xm <<= 64 - (DP_MBITS + 1); + ym <<= 64 - (DP_MBITS + 1); + + /* multiply 32bits xm,ym to give high 32bits rm with stickness + */ + + /* 32 * 32 => 64 */ +#define DPXMULT(x,y) ((unsigned long long)(x) * (unsigned long long)y) + + { + unsigned lxm = xm; + unsigned hxm = xm >> 32; + unsigned lym = ym; + unsigned hym = ym >> 32; + unsigned long long lrm; + unsigned long long hrm; + + lrm = DPXMULT(lxm, lym); + hrm = DPXMULT(hxm, hym); + + { + unsigned long long t = DPXMULT(lxm, hym); + { + unsigned long long at = + lrm + (t << 32); + hrm += at < lrm; + lrm = at; + } + hrm = hrm + (t >> 32); + } + + { + unsigned long long t = DPXMULT(hxm, lym); + { + unsigned long long at = + lrm + (t << 32); + hrm += at < lrm; + lrm = at; + } + hrm = hrm + (t >> 32); + } + rm = hrm | (lrm != 0); + } + + /* + * sticky shift down to normal rounding precision + */ + if ((signed long long) rm < 0) { + rm = + (rm >> (64 - (DP_MBITS + 1 + 3))) | + ((rm << (DP_MBITS + 1 + 3)) != 0); + re++; + } else { + rm = + (rm >> (64 - (DP_MBITS + 1 + 3 + 1))) | + ((rm << (DP_MBITS + 1 + 3 + 1)) != 0); + } + assert(rm & (DP_HIDDEN_BIT << 3)); + DPNORMRET2(rs, re, rm, "mul", x, y); + } +} diff --git a/arch/mips64/math-emu/dp_scalb.c b/arch/mips64/math-emu/dp_scalb.c new file mode 100644 index 000000000000..bb01461836b9 --- /dev/null +++ b/arch/mips64/math-emu/dp_scalb.c @@ -0,0 +1,58 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_scalb(ieee754dp x, int n) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + return ieee754dp_nanxcpt(x, "scalb", x, n); + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + return x; + case IEEE754_CLASS_DNORM: + DPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + DPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n); +} + + +ieee754dp ieee754dp_ldexp(ieee754dp x, int n) +{ + return ieee754dp_scalb(x, n); +} diff --git a/arch/mips64/math-emu/dp_simple.c b/arch/mips64/math-emu/dp_simple.c new file mode 100644 index 000000000000..f57eee2219ca --- /dev/null +++ b/arch/mips64/math-emu/dp_simple.c @@ -0,0 +1,66 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +int ieee754dp_finite(ieee754dp x) +{ + return DPBEXP(x) != DP_EMAX + 1 + DP_EBIAS; +} + +ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y) +{ + CLEARCX; + DPSIGN(x) = DPSIGN(y); + return x; +} + + +ieee754dp ieee754dp_neg(ieee754dp x) +{ + CLEARCX; + + if (ieee754dp_isnan(x)) /* but not infinity */ + return ieee754dp_nanxcpt(x, "neg", x); + + /* quick fix up */ + DPSIGN(x) ^= 1; + return x; +} + + +ieee754dp ieee754dp_abs(ieee754dp x) +{ + CLEARCX; + + if (ieee754dp_isnan(x)) /* but not infinity */ + return ieee754dp_nanxcpt(x, "abs", x); + + /* quick fix up */ + DPSIGN(x) = 0; + return x; +} diff --git a/arch/mips64/math-emu/dp_sqrt.c b/arch/mips64/math-emu/dp_sqrt.c new file mode 100644 index 000000000000..1f9fa9cb8f82 --- /dev/null +++ b/arch/mips64/math-emu/dp_sqrt.c @@ -0,0 +1,167 @@ +/* IEEE754 floating point arithmetic + * double precision square root + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +static const struct ieee754dp_konst knan = { +#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) + 0, 0, DP_EBIAS + DP_EMAX + 1, 0 +#else + 0, DP_EBIAS + DP_EMAX + 1, 0, 0 +#endif +}; + +#define nan ((ieee754dp)knan) + +static const unsigned table[] = { + 0, 1204, 3062, 5746, 9193, 13348, 18162, 23592, + 29598, 36145, 43202, 50740, 58733, 67158, 75992, + 85215, 83599, 71378, 60428, 50647, 41945, 34246, + 27478, 21581, 16499, 12183, 8588, 5674, 3403, + 1742, 661, 130 +}; + +ieee754dp ieee754dp_sqrt(ieee754dp x) +{ + struct ieee754_csr oldcsr; + ieee754dp y, z, t; + unsigned scalx, yh; + COMPXDP; + + EXPLODEXDP; + + /* x == INF or NAN? */ + switch (xc) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + /* sqrt(Nan) = Nan */ + return ieee754dp_nanxcpt(x, "sqrt"); + case IEEE754_CLASS_ZERO: + /* sqrt(0) = 0 */ + return x; + case IEEE754_CLASS_INF: + if (xs) + /* sqrt(-Inf) = Nan */ + return ieee754dp_nanxcpt(nan, "sqrt"); + /* sqrt(+Inf) = Inf */ + return x; + case IEEE754_CLASS_DNORM: + DPDNORMX; + /* fall through */ + case IEEE754_CLASS_NORM: + if (xs) + /* sqrt(-x) = Nan */ + return ieee754dp_nanxcpt(nan, "sqrt"); + break; + } + + /* save old csr; switch off INX enable & flag; set RN rounding */ + oldcsr = ieee754_csr; + ieee754_csr.mx &= ~IEEE754_INEXACT; + ieee754_csr.sx &= ~IEEE754_INEXACT; + ieee754_csr.rm = IEEE754_RN; + + /* adjust exponent to prevent overflow */ + scalx = 0; + if (xe > 512) { /* x > 2**-512? */ + xe -= 512; /* x = x / 2**512 */ + scalx += 256; + } else if (xe < -512) { /* x < 2**-512? */ + xe += 512; /* x = x * 2**512 */ + scalx -= 256; + } + + y = x = builddp(0, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); + + /* magic initial approximation to almost 8 sig. bits */ + yh = y.bits >> 32; + yh = (yh >> 1) + 0x1ff80000; + yh = yh - table[(yh >> 15) & 31]; + y.bits = ((unsigned long long) yh << 32) | (y.bits & 0xffffffff); + + /* Heron's rule once with correction to improve to ~18 sig. bits */ + /* t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0; */ + t = ieee754dp_div(x, y); + y = ieee754dp_add(y, t); + y.bits -= 0x0010000600000000LL; + y.bits &= 0xffffffff00000000LL; + + /* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */ + /* t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */ + z = t = ieee754dp_mul(y, y); + t.parts.bexp += 0x001; + t = ieee754dp_add(t, z); + z = ieee754dp_mul(ieee754dp_sub(x, z), y); + + /* t=z/(t+x) ; pt[n0]+=0x00100000; y+=t; */ + t = ieee754dp_div(z, ieee754dp_add(t, x)); + t.parts.bexp += 0x001; + y = ieee754dp_add(y, t); + + /* twiddle last bit to force y correctly rounded */ + + /* set RZ, clear INEX flag */ + ieee754_csr.rm = IEEE754_RZ; + ieee754_csr.sx &= ~IEEE754_INEXACT; + + /* t=x/y; ...chopped quotient, possibly inexact */ + t = ieee754dp_div(x, y); + + if (ieee754_csr.sx & IEEE754_INEXACT || t.bits != y.bits) { + + if (!(ieee754_csr.sx & IEEE754_INEXACT)) + /* t = t-ulp */ + t.bits -= 1; + + /* add inexact to result status */ + oldcsr.cx |= IEEE754_INEXACT; + oldcsr.sx |= IEEE754_INEXACT; + + switch (oldcsr.rm) { + case IEEE754_RP: + y.bits += 1; + /* drop through */ + case IEEE754_RN: + t.bits += 1; + break; + } + + /* y=y+t; ...chopped sum */ + y = ieee754dp_add(y, t); + + /* adjust scalx for correctly rounded sqrt(x) */ + scalx -= 1; + } + + /* py[n0]=py[n0]+scalx; ...scale back y */ + y.parts.bexp += scalx; + + /* restore rounding mode, possibly set inexact */ + ieee754_csr = oldcsr; + + return y; +} diff --git a/arch/mips64/math-emu/dp_sub.c b/arch/mips64/math-emu/dp_sub.c new file mode 100644 index 000000000000..a56d352fc156 --- /dev/null +++ b/arch/mips64/math-emu/dp_sub.c @@ -0,0 +1,194 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) +{ + COMPXDP; + COMPYDP; + + CLEARCX; + + EXPLODEXDP; + EXPLODEYDP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "sub", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y, "sub", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x, "sub", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754dp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Inifity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (xs != ys) + return x; + SETCX(IEEE754_INVALID_OPERATION); + return ieee754dp_xcpt(ieee754dp_indef(), "sub", x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + return ieee754dp_inf(ys ^ 1); + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return x; + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs != ys) + return x; + else + return ieee754dp_zero(ieee754_csr.rm == + IEEE754_RD); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + /* quick fix up */ + DPSIGN(y) ^= 1; + return y; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + /* FAAL THOROUGH */ + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + /* normalize ym,ye */ + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + /* normalize xm,xe */ + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + /* flip sign of y and handle as add */ + ys ^= 1; + + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + + /* provide guard,round and stick bit dpace */ + xm <<= 3; + ym <<= 3; + + if (xe > ye) { + /* have to shift y fraction right to align + */ + int s = xe - ye; + ym = XDPSRS(ym, s); + ye += s; + } else if (ye > xe) { + /* have to shift x fraction right to align + */ + int s = ye - xe; + xm = XDPSRS(xm, s); + xe += s; + } + assert(xe == ye); + assert(xe <= DP_EMAX); + + if (xs == ys) { + /* generate 28 bit result of adding two 27 bit numbers + */ + xm = xm + ym; + xe = xe; + xs = xs; + + if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */ + xm = XDPSRS1(xm); /* shift preserving sticky */ + xe++; + } + } else { + if (xm >= ym) { + xm = xm - ym; + xe = xe; + xs = xs; + } else { + xm = ym - xm; + xe = xe; + xs = ys; + } + if (xm == 0) { + if (ieee754_csr.rm == IEEE754_RD) + return ieee754dp_zero(1); /* round negative inf. => sign = -1 */ + else + return ieee754dp_zero(0); /* other round modes => sign = 1 */ + } + + /* normalize to rounding precision + */ + while ((xm >> (DP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + DPNORMRET2(xs, xe, xm, "sub", x, y); +} diff --git a/arch/mips64/math-emu/dp_tint.c b/arch/mips64/math-emu/dp_tint.c new file mode 100644 index 000000000000..c8a151b268d0 --- /dev/null +++ b/arch/mips64/math-emu/dp_tint.c @@ -0,0 +1,88 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include <linux/kernel.h> +#include "ieee754dp.h" + +int ieee754dp_tint(ieee754dp x) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754si_xcpt(ieee754si_indef(), "fixdp", x); + case IEEE754_CLASS_INF: + SETCX(IEEE754_OVERFLOW); + return ieee754si_xcpt(ieee754si_indef(), "fixdp", x); + case IEEE754_CLASS_ZERO: + return 0; + case IEEE754_CLASS_DNORM: /* much to small */ + SETCX(IEEE754_UNDERFLOW); + return ieee754si_xcpt(0, "fixdp", x); + case IEEE754_CLASS_NORM: + break; + } + if (xe >= 31) { + SETCX(IEEE754_OVERFLOW); + return ieee754si_xcpt(ieee754si_indef(), "fix", x); + } + if (xe < 0) { + SETCX(IEEE754_UNDERFLOW); + return ieee754si_xcpt(0, "fix", x); + } + /* oh gawd */ + if (xe > DP_MBITS) { + xm <<= xe - DP_MBITS; + } else if (xe < DP_MBITS) { + /* XXX no rounding + */ + xm >>= DP_MBITS - xe; + } + if (xs) + return -xm; + else + return xm; +} + + +unsigned int ieee754dp_tuns(ieee754dp x) +{ + ieee754dp hb = ieee754dp_1e31(); + + /* what if x < 0 ?? */ + if (ieee754dp_lt(x, hb)) + return (unsigned) ieee754dp_tint(x); + + return (unsigned) ieee754dp_tint(ieee754dp_sub(x, hb)) | + ((unsigned) 1 << 31); +} diff --git a/arch/mips64/math-emu/dp_tlong.c b/arch/mips64/math-emu/dp_tlong.c new file mode 100644 index 000000000000..cc8cf0ff9507 --- /dev/null +++ b/arch/mips64/math-emu/dp_tlong.c @@ -0,0 +1,141 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +long long ieee754dp_tlong(ieee754dp x) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); + case IEEE754_CLASS_INF: + SETCX(IEEE754_OVERFLOW); + return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); + case IEEE754_CLASS_ZERO: + return 0; + case IEEE754_CLASS_DNORM: /* much too small */ + SETCX(IEEE754_UNDERFLOW); + return ieee754di_xcpt(0, "dp_tlong", x); + case IEEE754_CLASS_NORM: + break; + } + if (xe >= 63) { + SETCX(IEEE754_OVERFLOW); + return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); + } + if (xe < 0) { + if (ieee754_csr.rm == IEEE754_RU) { + if (xs) { /* Negative */ + return 0x0000000000000000LL; + } else { /* Positive */ + return 0x0000000000000001LL; + } + } else if (ieee754_csr.rm == IEEE754_RD) { + if (xs) { /* Negative , return -1 */ + return 0xffffffffffffffffLL; + } else { /* Positive */ + return 0x0000000000000000LL; + } + } else { + SETCX(IEEE754_UNDERFLOW); + return ieee754di_xcpt(0, "dp_tlong", x); + } + } + /* oh gawd */ + if (xe > DP_MBITS) { + xm <<= xe - DP_MBITS; + } else if (xe < DP_MBITS) { + unsigned long long residue; + unsigned long long mask = 0; + int i; + int round; + int sticky; + int odd; + + /* compute mask */ + for (i = 0; i < DP_MBITS - xe; i++) { + mask = mask << 1; + mask = mask | 0x1; + } + residue = (xm & mask) << (64 - (DP_MBITS - xe)); + round = + ((0x8000000000000000LL & residue) != + 0x0000000000000000LL); + sticky = + ((0x7fffffffffffffffLL & residue) != + 0x0000000000000000LL); + + xm >>= DP_MBITS - xe; + + odd = ((xm & 0x1) != 0x0000000000000000LL); + + /* Do the rounding */ + if (!round && sticky) { + if ((ieee754_csr.rm == IEEE754_RU && !xs) + || (ieee754_csr.rm == IEEE754_RD && xs)) { + xm++; + } + } else if (round && !sticky) { + if ((ieee754_csr.rm == IEEE754_RU && !xs) + || (ieee754_csr.rm == IEEE754_RD && xs) + || (ieee754_csr.rm == IEEE754_RN && odd)) { + xm++; + } + } else if (round && sticky) { + if ((ieee754_csr.rm == IEEE754_RU && !xs) + || (ieee754_csr.rm == IEEE754_RD && xs) + || (ieee754_csr.rm == IEEE754_RN)) { + xm++; + } + } + } + if (xs) + return -xm; + else + return xm; +} + + +unsigned long long ieee754dp_tulong(ieee754dp x) +{ + ieee754dp hb = ieee754dp_1e63(); + + /* what if x < 0 ?? */ + if (ieee754dp_lt(x, hb)) + return (unsigned long long) ieee754dp_tlong(x); + + return (unsigned long long) ieee754dp_tlong(ieee754dp_sub(x, hb)) | + (1ULL << 63); +} diff --git a/arch/mips64/math-emu/ieee754.c b/arch/mips64/math-emu/ieee754.c new file mode 100644 index 000000000000..5e86e40c678f --- /dev/null +++ b/arch/mips64/math-emu/ieee754.c @@ -0,0 +1,138 @@ +/* ieee754 floating point arithmetic + * single and double precision + * + * BUGS + * not much dp done + * doesnt generate IEEE754_INEXACT + * + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754int.h" + +#define DP_EBIAS 1023 +#define DP_EMIN (-1022) +#define DP_EMAX 1023 + +#define SP_EBIAS 127 +#define SP_EMIN (-126) +#define SP_EMAX 127 + +/* indexed by class */ +const char *const ieee754_cname[] = { + "Normal", + "Zero", + "Denormal", + "Infinity", + "QNaN", + "SNaN", +}; + +/* the control status register +*/ +struct ieee754_csr ieee754_csr; + +/* special constants +*/ + + +#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) +#define SPSTR(s,b,m) {m,b,s} +#define DPSTR(s,b,mh,ml) {ml,mh,b,s} +#endif + +#ifdef __MIPSEB__ +#define SPSTR(s,b,m) {s,b,m} +#define DPSTR(s,b,mh,ml) {s,b,mh,ml} +#endif + +const struct ieee754dp_konst __ieee754dp_spcvals[] = { + DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* + zero */ + DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* - zero */ + DPSTR(0, DP_EBIAS, 0, 0), /* + 1.0 */ + DPSTR(1, DP_EBIAS, 0, 0), /* - 1.0 */ + DPSTR(0, 3 + DP_EBIAS, 0x40000, 0), /* + 10.0 */ + DPSTR(1, 3 + DP_EBIAS, 0x40000, 0), /* - 10.0 */ + DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* + infinity */ + DPSTR(1, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* - infinity */ + DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0x40000, 0), /* + indef quiet Nan */ + DPSTR(0, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* + max */ + DPSTR(1, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* - max */ + DPSTR(0, DP_EMIN + DP_EBIAS, 0, 0), /* + min normal */ + DPSTR(1, DP_EMIN + DP_EBIAS, 0, 0), /* - min normal */ + DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* + min denormal */ + DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* - min denormal */ + DPSTR(0, 31 + DP_EBIAS, 0, 0), /* + 1.0e31 */ + DPSTR(0, 63 + DP_EBIAS, 0, 0), /* + 1.0e63 */ +}; + +const struct ieee754sp_konst __ieee754sp_spcvals[] = { + SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 0), /* + zero */ + SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 0), /* - zero */ + SPSTR(0, SP_EBIAS, 0), /* + 1.0 */ + SPSTR(1, SP_EBIAS, 0), /* - 1.0 */ + SPSTR(0, 3 + SP_EBIAS, 0x200000), /* + 10.0 */ + SPSTR(1, 3 + SP_EBIAS, 0x200000), /* - 10.0 */ + SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0), /* + infinity */ + SPSTR(1, SP_EMAX + 1 + SP_EBIAS, 0), /* - infinity */ + SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0x200000), /* + indef quiet Nan */ + SPSTR(0, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* + max normal */ + SPSTR(1, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* - max normal */ + SPSTR(0, SP_EMIN + SP_EBIAS, 0), /* + min normal */ + SPSTR(1, SP_EMIN + SP_EBIAS, 0), /* - min normal */ + SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 1), /* + min denormal */ + SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 1), /* - min denormal */ + SPSTR(0, 31 + SP_EBIAS, 0), /* + 1.0e31 */ + SPSTR(0, 63 + SP_EBIAS, 0), /* + 1.0e63 */ +}; + + +int ieee754si_xcpt(int r, const char *op, ...) +{ + struct ieee754xctx ax; + + if (!TSTX()) + return r; + ax.op = op; + ax.rt = IEEE754_RT_SI; + ax.rv.si = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.si; +} + +long long ieee754di_xcpt(long long r, const char *op, ...) +{ + struct ieee754xctx ax; + + if (!TSTX()) + return r; + ax.op = op; + ax.rt = IEEE754_RT_DI; + ax.rv.di = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.di; +} diff --git a/arch/mips64/math-emu/ieee754.h b/arch/mips64/math-emu/ieee754.h new file mode 100644 index 000000000000..ad2c91aed0b1 --- /dev/null +++ b/arch/mips64/math-emu/ieee754.h @@ -0,0 +1,490 @@ +/* single and double precision fp ops + * missing extended precision. +*/ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + +/************************************************************************** + * Nov 7, 2000 + * Modification to allow integration with Linux kernel + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ + +#ifdef __KERNEL__ +/* Going from Algorithmics to Linux native environment, add this */ +#include <linux/types.h> + +/* + * Not very pretty, but the Linux kernel's normal va_list definition + * does not allow it to be used as a structure element, as it is here. + */ +#ifndef _STDARG_H +#include <stdarg.h> +#endif + +#else + +/* Note that __KERNEL__ is taken to mean Linux kernel */ + +#if #system(OpenBSD) +#include <machine/types.h> +#endif +#include <machine/endian.h> + +#endif /* __KERNEL__ */ + +#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) +struct ieee754dp_konst { + unsigned mantlo:32; + unsigned manthi:20; + unsigned bexp:11; + unsigned sign:1; +}; +struct ieee754sp_konst { + unsigned mant:23; + unsigned bexp:8; + unsigned sign:1; +}; + +typedef union _ieee754dp { + struct ieee754dp_konst oparts; + struct { + unsigned long long mant:52; + unsigned int bexp:11; + unsigned int sign:1; + } parts; + unsigned long long bits; + double d; +} ieee754dp; + +typedef union _ieee754sp { + struct ieee754sp_konst parts; + float f; + unsigned long bits; +} ieee754sp; +#endif + +#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) +struct ieee754dp_konst { + unsigned sign:1; + unsigned bexp:11; + unsigned manthi:20; + unsigned mantlo:32; +}; +typedef union _ieee754dp { + struct ieee754dp_konst oparts; + struct { + unsigned int sign:1; + unsigned int bexp:11; + unsigned long long mant:52; + } parts; + double d; + unsigned long long bits; +} ieee754dp; + +struct ieee754sp_konst { + unsigned sign:1; + unsigned bexp:8; + unsigned mant:23; +}; + +typedef union _ieee754sp { + struct ieee754sp_konst parts; + float f; + unsigned long bits; +} ieee754sp; +#endif + +/* + * single precision (often aka float) +*/ +int ieee754sp_finite(ieee754sp x); +int ieee754sp_class(ieee754sp x); + +ieee754sp ieee754sp_abs(ieee754sp x); +ieee754sp ieee754sp_neg(ieee754sp x); +ieee754sp ieee754sp_scalb(ieee754sp x, int); +ieee754sp ieee754sp_logb(ieee754sp x); + +/* x with sign of y */ +ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y); + +ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y); +ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y); +ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y); +ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y); + +ieee754sp ieee754sp_fint(int x); +ieee754sp ieee754sp_funs(unsigned x); +ieee754sp ieee754sp_flong(long long x); +ieee754sp ieee754sp_fulong(unsigned long long x); +ieee754sp ieee754sp_fdp(ieee754dp x); + +int ieee754sp_tint(ieee754sp x); +unsigned int ieee754sp_tuns(ieee754sp x); +long long ieee754sp_tlong(ieee754sp x); +unsigned long long ieee754sp_tulong(ieee754sp x); + +int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cop); +/* + * basic sp math + */ +ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip); +ieee754sp ieee754sp_frexp(ieee754sp x, int *exp); +ieee754sp ieee754sp_ldexp(ieee754sp x, int exp); + +ieee754sp ieee754sp_ceil(ieee754sp x); +ieee754sp ieee754sp_floor(ieee754sp x); +ieee754sp ieee754sp_trunc(ieee754sp x); + +ieee754sp ieee754sp_sqrt(ieee754sp x); + +/* + * double precision (often aka double) +*/ +int ieee754dp_finite(ieee754dp x); +int ieee754dp_class(ieee754dp x); + +/* x with sign of y */ +ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y); + +ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y); +ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y); +ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y); +ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y); + +ieee754dp ieee754dp_abs(ieee754dp x); +ieee754dp ieee754dp_neg(ieee754dp x); +ieee754dp ieee754dp_scalb(ieee754dp x, int); + +/* return exponent as integer in floating point format + */ +ieee754dp ieee754dp_logb(ieee754dp x); + +ieee754dp ieee754dp_fint(int x); +ieee754dp ieee754dp_funs(unsigned x); +ieee754dp ieee754dp_flong(long long x); +ieee754dp ieee754dp_fulong(unsigned long long x); +ieee754dp ieee754dp_fsp(ieee754sp x); + +ieee754dp ieee754dp_ceil(ieee754dp x); +ieee754dp ieee754dp_floor(ieee754dp x); +ieee754dp ieee754dp_trunc(ieee754dp x); + +int ieee754dp_tint(ieee754dp x); +unsigned int ieee754dp_tuns(ieee754dp x); +long long ieee754dp_tlong(ieee754dp x); +unsigned long long ieee754dp_tulong(ieee754dp x); + +int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cop); +/* + * basic sp math + */ +ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip); +ieee754dp ieee754dp_frexp(ieee754dp x, int *exp); +ieee754dp ieee754dp_ldexp(ieee754dp x, int exp); + +ieee754dp ieee754dp_ceil(ieee754dp x); +ieee754dp ieee754dp_floor(ieee754dp x); +ieee754dp ieee754dp_trunc(ieee754dp x); + +ieee754dp ieee754dp_sqrt(ieee754dp x); + + + +/* 5 types of floating point number +*/ +#define IEEE754_CLASS_NORM 0x00 +#define IEEE754_CLASS_ZERO 0x01 +#define IEEE754_CLASS_DNORM 0x02 +#define IEEE754_CLASS_INF 0x03 +#define IEEE754_CLASS_SNAN 0x04 +#define IEEE754_CLASS_QNAN 0x05 +extern const char *const ieee754_cname[]; + +/* exception numbers */ +#define IEEE754_INEXACT 0x01 +#define IEEE754_UNDERFLOW 0x02 +#define IEEE754_OVERFLOW 0x04 +#define IEEE754_ZERO_DIVIDE 0x08 +#define IEEE754_INVALID_OPERATION 0x10 + +/* cmp operators +*/ +#define IEEE754_CLT 0x01 +#define IEEE754_CEQ 0x02 +#define IEEE754_CGT 0x04 +#define IEEE754_CUN 0x08 + +/* rounding mode +*/ +#define IEEE754_RN 0 /* round to nearest */ +#define IEEE754_RZ 1 /* round toward zero */ +#define IEEE754_RD 2 /* round toward -Infinity */ +#define IEEE754_RU 3 /* round toward +Infinity */ + +/* other naming */ +#define IEEE754_RM IEEE754_RD +#define IEEE754_RP IEEE754_RU + +/* "normal" comparisons +*/ +static __inline int ieee754sp_eq(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CEQ); +} + +static __inline int ieee754sp_ne(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, + IEEE754_CLT | IEEE754_CGT | IEEE754_CUN); +} + +static __inline int ieee754sp_lt(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CLT); +} + +static __inline int ieee754sp_le(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ); +} + +static __inline int ieee754sp_gt(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CGT); +} + + +static __inline int ieee754sp_ge(ieee754sp x, ieee754sp y) +{ + return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ); +} + +static __inline int ieee754dp_eq(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CEQ); +} + +static __inline int ieee754dp_ne(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, + IEEE754_CLT | IEEE754_CGT | IEEE754_CUN); +} + +static __inline int ieee754dp_lt(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CLT); +} + +static __inline int ieee754dp_le(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ); +} + +static __inline int ieee754dp_gt(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CGT); +} + +static __inline int ieee754dp_ge(ieee754dp x, ieee754dp y) +{ + return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ); +} + + +/* like strtod +*/ +ieee754dp ieee754dp_fstr(const char *s, char **endp); +char *ieee754dp_tstr(ieee754dp x, int prec, int fmt, int af); + + +/* the control status register +*/ +struct ieee754_csr { + unsigned pad:13; + unsigned noq:1; /* set 1 for no quiet NaN's */ + unsigned nod:1; /* set 1 for no denormalised numbers */ + unsigned cx:5; /* exceptions this operation */ + unsigned mx:5; /* exception enable mask */ + unsigned sx:5; /* exceptions total */ + unsigned rm:2; /* current rounding mode */ +}; +extern struct ieee754_csr ieee754_csr; + +static __inline unsigned ieee754_getrm(void) +{ + return (ieee754_csr.rm); +} +static __inline unsigned ieee754_setrm(unsigned rm) +{ + return (ieee754_csr.rm = rm); +} + +/* + * get current exceptions + */ +static __inline unsigned ieee754_getcx(void) +{ + return (ieee754_csr.cx); +} + +/* test for current exception condition + */ +static __inline int ieee754_cxtest(unsigned n) +{ + return (ieee754_csr.cx & n); +} + +/* + * get sticky exceptions + */ +static __inline unsigned ieee754_getsx(void) +{ + return (ieee754_csr.sx); +} + +/* clear sticky conditions +*/ +static __inline unsigned ieee754_clrsx(void) +{ + return (ieee754_csr.sx = 0); +} + +/* test for sticky exception condition + */ +static __inline int ieee754_sxtest(unsigned n) +{ + return (ieee754_csr.sx & n); +} + +/* debugging */ +ieee754sp ieee754sp_dump(char *s, ieee754sp x); +ieee754dp ieee754dp_dump(char *s, ieee754dp x); + +#define IEEE754_SPCVAL_PZERO 0 +#define IEEE754_SPCVAL_NZERO 1 +#define IEEE754_SPCVAL_PONE 2 +#define IEEE754_SPCVAL_NONE 3 +#define IEEE754_SPCVAL_PTEN 4 +#define IEEE754_SPCVAL_NTEN 5 +#define IEEE754_SPCVAL_PINFINITY 6 +#define IEEE754_SPCVAL_NINFINITY 7 +#define IEEE754_SPCVAL_INDEF 8 +#define IEEE754_SPCVAL_PMAX 9 /* +max norm */ +#define IEEE754_SPCVAL_NMAX 10 /* -max norm */ +#define IEEE754_SPCVAL_PMIN 11 /* +min norm */ +#define IEEE754_SPCVAL_NMIN 12 /* +min norm */ +#define IEEE754_SPCVAL_PMIND 13 /* +min denorm */ +#define IEEE754_SPCVAL_NMIND 14 /* +min denorm */ +#define IEEE754_SPCVAL_P1E31 15 /* + 1.0e31 */ +#define IEEE754_SPCVAL_P1E63 16 /* + 1.0e63 */ + +extern const struct ieee754dp_konst __ieee754dp_spcvals[]; +extern const struct ieee754sp_konst __ieee754sp_spcvals[]; +#define ieee754dp_spcvals ((const ieee754dp *)__ieee754dp_spcvals) +#define ieee754sp_spcvals ((const ieee754sp *)__ieee754sp_spcvals) + +/* return infinity with given sign +*/ +#define ieee754dp_inf(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)]) +#define ieee754dp_zero(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) +#define ieee754dp_one(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) +#define ieee754dp_ten(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) +#define ieee754dp_indef() \ + (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF]) +#define ieee754dp_max(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) +#define ieee754dp_min(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) +#define ieee754dp_mind(sn) \ + (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) +#define ieee754dp_1e31() \ + (ieee754dp_spcvals[IEEE754_SPCVAL_P1E31]) +#define ieee754dp_1e63() \ + (ieee754dp_spcvals[IEEE754_SPCVAL_P1E63]) + +#define ieee754sp_inf(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)]) +#define ieee754sp_zero(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) +#define ieee754sp_one(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) +#define ieee754sp_ten(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) +#define ieee754sp_indef() \ + (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF]) +#define ieee754sp_max(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) +#define ieee754sp_min(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) +#define ieee754sp_mind(sn) \ + (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) +#define ieee754sp_1e31() \ + (ieee754sp_spcvals[IEEE754_SPCVAL_P1E31]) +#define ieee754sp_1e63() \ + (ieee754sp_spcvals[IEEE754_SPCVAL_P1E63]) + +/* indefinite integer value +*/ +#define ieee754si_indef() INT_MIN +#ifdef LONG_LONG_MIN +#define ieee754di_indef() LONG_LONG_MIN +#else +#define ieee754di_indef() (-9223372036854775807LL-1) +#endif + +/* IEEE exception context, passed to handler */ +struct ieee754xctx { + const char *op; /* operation name */ + int rt; /* result type */ + union { + ieee754sp sp; /* single precision */ + ieee754dp dp; /* double precision */ +#ifdef IEEE854_XP + ieee754xp xp; /* extended precision */ +#endif + int si; /* standard signed integer (32bits) */ + long long di; /* extended signed integer (64bits) */ + } rv; /* default result format implied by op */ + va_list ap; +}; + +/* result types for xctx.rt */ +#define IEEE754_RT_SP 0 +#define IEEE754_RT_DP 1 +#define IEEE754_RT_XP 2 +#define IEEE754_RT_SI 3 +#define IEEE754_RT_DI 4 + +extern void ieee754_xcpt(struct ieee754xctx *xcp); + +/* compat */ +#define ieee754dp_fix(x) ieee754dp_tint(x) +#define ieee754sp_fix(x) ieee754sp_tint(x) diff --git a/arch/mips64/math-emu/ieee754d.c b/arch/mips64/math-emu/ieee754d.c new file mode 100644 index 000000000000..b25c8c03d003 --- /dev/null +++ b/arch/mips64/math-emu/ieee754d.c @@ -0,0 +1,142 @@ +/* some debug functions +*/ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + +/************************************************************************** + * Nov 7, 2000 + * Modified to build and operate in Linux kernel environment. + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ + +#include "ieee754.h" + +#define DP_EBIAS 1023 +#define DP_EMIN (-1022) +#define DP_EMAX 1023 +#define DP_FBITS 52 + +#define SP_EBIAS 127 +#define SP_EMIN (-126) +#define SP_EMAX 127 +#define SP_FBITS 23 + +#define DP_MBIT(x) ((unsigned long long)1 << (x)) +#define DP_HIDDEN_BIT DP_MBIT(DP_FBITS) +#define DP_SIGN_BIT DP_MBIT(63) + + +#define SP_MBIT(x) ((unsigned long)1 << (x)) +#define SP_HIDDEN_BIT SP_MBIT(SP_FBITS) +#define SP_SIGN_BIT SP_MBIT(31) + + +#define SPSIGN(sp) (sp.parts.sign) +#define SPBEXP(sp) (sp.parts.bexp) +#define SPMANT(sp) (sp.parts.mant) + +#define DPSIGN(dp) (dp.parts.sign) +#define DPBEXP(dp) (dp.parts.bexp) +#define DPMANT(dp) (dp.parts.mant) + +ieee754dp ieee754dp_dump(char *m, ieee754dp x) +{ + int i; + + printk("%s", m); + printk("<%08x,%08x>\n", (unsigned) (x.bits >> 32), + (unsigned) x.bits); + printk("\t="); + switch (ieee754dp_class(x)) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + printk("Nan %c", DPSIGN(x) ? '-' : '+'); + for (i = DP_FBITS - 1; i >= 0; i--) + printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0'); + break; + case IEEE754_CLASS_INF: + printk("%cInfinity", DPSIGN(x) ? '-' : '+'); + break; + case IEEE754_CLASS_ZERO: + printk("%cZero", DPSIGN(x) ? '-' : '+'); + break; + case IEEE754_CLASS_DNORM: + printk("%c0.", DPSIGN(x) ? '-' : '+'); + for (i = DP_FBITS - 1; i >= 0; i--) + printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0'); + printk("e%d", DPBEXP(x) - DP_EBIAS); + break; + case IEEE754_CLASS_NORM: + printk("%c1.", DPSIGN(x) ? '-' : '+'); + for (i = DP_FBITS - 1; i >= 0; i--) + printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0'); + printk("e%d", DPBEXP(x) - DP_EBIAS); + break; + default: + printk("Illegal/Unknown IEEE754 value class"); + } + printk("\n"); + return x; +} + +ieee754sp ieee754sp_dump(char *m, ieee754sp x) +{ + int i; + + printk("%s=", m); + printk("<%08x>\n", (unsigned) x.bits); + printk("\t="); + switch (ieee754sp_class(x)) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + printk("Nan %c", SPSIGN(x) ? '-' : '+'); + for (i = SP_FBITS - 1; i >= 0; i--) + printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0'); + break; + case IEEE754_CLASS_INF: + printk("%cInfinity", SPSIGN(x) ? '-' : '+'); + break; + case IEEE754_CLASS_ZERO: + printk("%cZero", SPSIGN(x) ? '-' : '+'); + break; + case IEEE754_CLASS_DNORM: + printk("%c0.", SPSIGN(x) ? '-' : '+'); + for (i = SP_FBITS - 1; i >= 0; i--) + printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0'); + printk("e%d", SPBEXP(x) - SP_EBIAS); + break; + case IEEE754_CLASS_NORM: + printk("%c1.", SPSIGN(x) ? '-' : '+'); + for (i = SP_FBITS - 1; i >= 0; i--) + printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0'); + printk("e%d", SPBEXP(x) - SP_EBIAS); + break; + default: + printk("Illegal/Unknown IEEE754 value class"); + } + printk("\n"); + return x; +} + diff --git a/arch/mips64/math-emu/ieee754dp.c b/arch/mips64/math-emu/ieee754dp.c new file mode 100644 index 000000000000..0943d56ecfe1 --- /dev/null +++ b/arch/mips64/math-emu/ieee754dp.c @@ -0,0 +1,197 @@ +/* IEEE754 floating point arithmetic + * double precision: common utilities + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754dp.h" + +int ieee754dp_class(ieee754dp x) +{ + COMPXDP; + EXPLODEXDP; + return xc; +} + +int ieee754dp_isnan(ieee754dp x) +{ + return ieee754dp_class(x) >= IEEE754_CLASS_SNAN; +} + +int ieee754dp_issnan(ieee754dp x) +{ + assert(ieee754dp_isnan(x)); + if (ieee754_csr.noq) + return 1; + return !(DPMANT(x) & DP_MBIT(DP_MBITS - 1)); +} + + +ieee754dp ieee754dp_xcpt(ieee754dp r, const char *op, ...) +{ + struct ieee754xctx ax; + if (!TSTX()) + return r; + + ax.op = op; + ax.rt = IEEE754_RT_DP; + ax.rv.dp = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.dp; +} + +ieee754dp ieee754dp_nanxcpt(ieee754dp r, const char *op, ...) +{ + struct ieee754xctx ax; + + assert(ieee754dp_isnan(r)); + + if (!ieee754dp_issnan(r)) /* QNAN does not cause invalid op !! */ + return r; + + if (!SETCX(IEEE754_INVALID_OPERATION)) { + /* not enabled convert to a quiet NaN */ + if (ieee754_csr.noq) + return r; + DPMANT(r) |= DP_MBIT(DP_MBITS - 1); + return r; + } + + ax.op = op; + ax.rt = 0; + ax.rv.dp = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.dp; +} + +ieee754dp ieee754dp_bestnan(ieee754dp x, ieee754dp y) +{ + assert(ieee754dp_isnan(x)); + assert(ieee754dp_isnan(y)); + + if (DPMANT(x) > DPMANT(y)) + return x; + else + return y; +} + + +/* generate a normal/denormal number with over,under handeling + * sn is sign + * xe is an unbiased exponent + * xm is 3bit extended precision value. + */ +ieee754dp ieee754dp_format(int sn, int xe, unsigned long long xm) +{ + assert(xm); /* we dont gen exact zeros (probably should) */ + + assert((xm >> (DP_MBITS + 1 + 3)) == 0); /* no execess */ + assert(xm & (DP_HIDDEN_BIT << 3)); + + if (xe < DP_EMIN) { + /* strip lower bits */ + int es = DP_EMIN - xe; + + if (ieee754_csr.nod) { + SETCX(IEEE754_UNDERFLOW); + return ieee754dp_zero(sn); + } + + /* sticky right shift es bits + */ + xm = XDPSRS(xm, es); + xe += es; + + assert((xm & (DP_HIDDEN_BIT << 3)) == 0); + assert(xe == DP_EMIN); + } + if (xm & (DP_MBIT(3) - 1)) { + SETCX(IEEE754_INEXACT); + /* inexact must round of 3 bits + */ + switch (ieee754_csr.rm) { + case IEEE754_RZ: + break; + case IEEE754_RN: + xm += 0x3 + ((xm >> 3) & 1); + /* xm += (xm&0x8)?0x4:0x3 */ + break; + case IEEE754_RU: /* toward +Infinity */ + if (!sn) /* ?? */ + xm += 0x8; + break; + case IEEE754_RD: /* toward -Infinity */ + if (sn) /* ?? */ + xm += 0x8; + break; + } + /* adjust exponent for rounding add overflowing + */ + if (xm >> (DP_MBITS + 3 + 1)) { /* add causes mantissa overflow */ + xm >>= 1; + xe++; + } + } + /* strip grs bits */ + xm >>= 3; + + assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ + assert(xe >= DP_EMIN); + + if (xe > DP_EMAX) { + SETCX(IEEE754_OVERFLOW); + /* -O can be table indexed by (rm,sn) */ + switch (ieee754_csr.rm) { + case IEEE754_RN: + return ieee754dp_inf(sn); + case IEEE754_RZ: + return ieee754dp_max(sn); + case IEEE754_RU: /* toward +Infinity */ + if (sn == 0) + return ieee754dp_inf(0); + else + return ieee754dp_max(1); + case IEEE754_RD: /* toward -Infinity */ + if (sn == 0) + return ieee754dp_max(0); + else + return ieee754dp_inf(1); + } + } + /* gen norm/denorm/zero */ + + if ((xm & DP_HIDDEN_BIT) == 0) { + /* we underflow (tiny/zero) */ + assert(xe == DP_EMIN); + SETCX(IEEE754_UNDERFLOW); + return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm); + } else { + assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ + assert(xm & DP_HIDDEN_BIT); + + return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); + } +} diff --git a/arch/mips64/math-emu/ieee754dp.h b/arch/mips64/math-emu/ieee754dp.h new file mode 100644 index 000000000000..8ab3e0148ab9 --- /dev/null +++ b/arch/mips64/math-emu/ieee754dp.h @@ -0,0 +1,83 @@ +/* + * IEEE754 floating point + * double precision internal header file + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754int.h" + +#define assert(expr) ((void)0) + +/* 3bit extended double precision sticky right shift */ +#define XDPSRS(v,rs) \ + ((rs > (DP_MBITS+3))?1:((v) >> (rs)) | ((v) << (64-(rs)) != 0)) + +#define XDPSRSX1() \ + (xe++, (xm = (xm >> 1) | (xm & 1))) + +#define XDPSRS1(v) \ + (((v) >> 1) | ((v) & 1)) + +/* convert denormal to normalized with extended exponent */ +#define DPDNORMx(m,e) \ + while( (m >> DP_MBITS) == 0) { m <<= 1; e--; } +#define DPDNORMX DPDNORMx(xm,xe) +#define DPDNORMY DPDNORMx(ym,ye) + +static __inline ieee754dp builddp(int s, int bx, unsigned long long m) +{ + ieee754dp r; + + assert((s) == 0 || (s) == 1); + assert((bx) >= DP_EMIN - 1 + DP_EBIAS + && (bx) <= DP_EMAX + 1 + DP_EBIAS); + assert(((m) >> DP_MBITS) == 0); + + r.parts.sign = s; + r.parts.bexp = bx; + r.parts.mant = m; + return r; +} + +extern int ieee754dp_isnan(ieee754dp); +extern int ieee754dp_issnan(ieee754dp); +extern int ieee754si_xcpt(int, const char *, ...); +extern long long ieee754di_xcpt(long long, const char *, ...); +extern ieee754dp ieee754dp_xcpt(ieee754dp, const char *, ...); +extern ieee754dp ieee754dp_nanxcpt(ieee754dp, const char *, ...); +extern ieee754dp ieee754dp_bestnan(ieee754dp, ieee754dp); +extern ieee754dp ieee754dp_format(int, int, unsigned long long); + + +#define DPNORMRET2(s,e,m,name,a0,a1) \ +{ \ + ieee754dp V = ieee754dp_format(s,e,m); \ + if(TSTX()) \ + return ieee754dp_xcpt(V,name,a0,a1); \ + else \ + return V; \ +} + +#define DPNORMRET1(s,e,m,name,a0) DPNORMRET2(s,e,m,name,a0,a0) diff --git a/arch/mips64/math-emu/ieee754int.h b/arch/mips64/math-emu/ieee754int.h new file mode 100644 index 000000000000..6de10131fd32 --- /dev/null +++ b/arch/mips64/math-emu/ieee754int.h @@ -0,0 +1,135 @@ +/* + * IEEE754 floating point + * common internal header file + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754.h" + +#define DP_EBIAS 1023 +#define DP_EMIN (-1022) +#define DP_EMAX 1023 +#define DP_MBITS 52 + +#define SP_EBIAS 127 +#define SP_EMIN (-126) +#define SP_EMAX 127 +#define SP_MBITS 23 + +#define DP_MBIT(x) ((unsigned long long)1 << (x)) +#define DP_HIDDEN_BIT DP_MBIT(DP_MBITS) +#define DP_SIGN_BIT DP_MBIT(63) + +#define SP_MBIT(x) ((unsigned long)1 << (x)) +#define SP_HIDDEN_BIT SP_MBIT(SP_MBITS) +#define SP_SIGN_BIT SP_MBIT(31) + + +#define SPSIGN(sp) (sp.parts.sign) +#define SPBEXP(sp) (sp.parts.bexp) +#define SPMANT(sp) (sp.parts.mant) + +#define DPSIGN(dp) (dp.parts.sign) +#define DPBEXP(dp) (dp.parts.bexp) +#define DPMANT(dp) (dp.parts.mant) + +#define CLPAIR(x,y) ((x)*6+(y)) + +#define CLEARCX \ + (ieee754_csr.cx = 0) + +#define SETCX(x) \ + (ieee754_csr.cx |= (x),ieee754_csr.sx |= (x),ieee754_csr.mx & (x)) + +#define TSTX() \ + (ieee754_csr.cx & ieee754_csr.mx) + + +#define COMPXSP \ + unsigned xm; int xe; int xs; int xc + +#define COMPYSP \ + unsigned ym; int ye; int ys; int yc + +#define EXPLODESP(v,vc,vs,ve,vm) \ +{\ + vs = SPSIGN(v);\ + ve = SPBEXP(v);\ + vm = SPMANT(v);\ + if(ve == SP_EMAX+1+SP_EBIAS){\ + if(vm == 0)\ + vc = IEEE754_CLASS_INF;\ + else if(vm & SP_MBIT(SP_MBITS-1)) \ + vc = IEEE754_CLASS_QNAN;\ + else \ + vc = IEEE754_CLASS_SNAN;\ + } else if(ve == SP_EMIN-1+SP_EBIAS) {\ + if(vm) {\ + ve = SP_EMIN;\ + vc = IEEE754_CLASS_DNORM;\ + } else\ + vc = IEEE754_CLASS_ZERO;\ + } else {\ + ve -= SP_EBIAS;\ + vm |= SP_HIDDEN_BIT;\ + vc = IEEE754_CLASS_NORM;\ + }\ +} +#define EXPLODEXSP EXPLODESP(x,xc,xs,xe,xm) +#define EXPLODEYSP EXPLODESP(y,yc,ys,ye,ym) + + +#define COMPXDP \ +unsigned long long xm; int xe; int xs; int xc + +#define COMPYDP \ +unsigned long long ym; int ye; int ys; int yc + +#define EXPLODEDP(v,vc,vs,ve,vm) \ +{\ + vm = DPMANT(v);\ + vs = DPSIGN(v);\ + ve = DPBEXP(v);\ + if(ve == DP_EMAX+1+DP_EBIAS){\ + if(vm == 0)\ + vc = IEEE754_CLASS_INF;\ + else if(vm & DP_MBIT(DP_MBITS-1)) \ + vc = IEEE754_CLASS_QNAN;\ + else \ + vc = IEEE754_CLASS_SNAN;\ + } else if(ve == DP_EMIN-1+DP_EBIAS) {\ + if(vm) {\ + ve = DP_EMIN;\ + vc = IEEE754_CLASS_DNORM;\ + } else\ + vc = IEEE754_CLASS_ZERO;\ + } else {\ + ve -= DP_EBIAS;\ + vm |= DP_HIDDEN_BIT;\ + vc = IEEE754_CLASS_NORM;\ + }\ +} +#define EXPLODEXDP EXPLODEDP(x,xc,xs,xe,xm) +#define EXPLODEYDP EXPLODEDP(y,yc,ys,ye,ym) diff --git a/arch/mips64/math-emu/ieee754m.c b/arch/mips64/math-emu/ieee754m.c new file mode 100644 index 000000000000..29b4e3376e6e --- /dev/null +++ b/arch/mips64/math-emu/ieee754m.c @@ -0,0 +1,56 @@ +/* + * floor, trunc, ceil + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754.h" + +ieee754dp ieee754dp_floor(ieee754dp x) +{ + ieee754dp i; + + if (ieee754dp_lt(ieee754dp_modf(x, &i), ieee754dp_zero(0))) + return ieee754dp_sub(i, ieee754dp_one(0)); + else + return i; +} + +ieee754dp ieee754dp_ceil(ieee754dp x) +{ + ieee754dp i; + + if (ieee754dp_gt(ieee754dp_modf(x, &i), ieee754dp_zero(0))) + return ieee754dp_add(i, ieee754dp_one(0)); + else + return i; +} + +ieee754dp ieee754dp_trunc(ieee754dp x) +{ + ieee754dp i; + + (void) ieee754dp_modf(x, &i); + return i; +} diff --git a/arch/mips64/math-emu/ieee754sp.c b/arch/mips64/math-emu/ieee754sp.c new file mode 100644 index 000000000000..511ec8de5b27 --- /dev/null +++ b/arch/mips64/math-emu/ieee754sp.c @@ -0,0 +1,197 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +int ieee754sp_class(ieee754sp x) +{ + COMPXSP; + EXPLODEXSP; + return xc; +} + +int ieee754sp_isnan(ieee754sp x) +{ + return ieee754sp_class(x) >= IEEE754_CLASS_SNAN; +} + +int ieee754sp_issnan(ieee754sp x) +{ + assert(ieee754sp_isnan(x)); + if (ieee754_csr.noq) + return 1; + return !(SPMANT(x) & SP_MBIT(SP_MBITS - 1)); +} + + +ieee754sp ieee754sp_xcpt(ieee754sp r, const char *op, ...) +{ + struct ieee754xctx ax; + + if (!TSTX()) + return r; + + ax.op = op; + ax.rt = IEEE754_RT_SP; + ax.rv.sp = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.sp; +} + +ieee754sp ieee754sp_nanxcpt(ieee754sp r, const char *op, ...) +{ + struct ieee754xctx ax; + + assert(ieee754sp_isnan(r)); + + if (!ieee754sp_issnan(r)) /* QNAN does not cause invalid op !! */ + return r; + + if (!SETCX(IEEE754_INVALID_OPERATION)) { + /* not enabled convert to a quiet NaN */ + if (ieee754_csr.noq) + return r; + SPMANT(r) |= SP_MBIT(SP_MBITS - 1); + return r; + } + + ax.op = op; + ax.rt = 0; + ax.rv.sp = r; + va_start(ax.ap, op); + ieee754_xcpt(&ax); + return ax.rv.sp; +} + +ieee754sp ieee754sp_bestnan(ieee754sp x, ieee754sp y) +{ + assert(ieee754sp_isnan(x)); + assert(ieee754sp_isnan(y)); + + if (SPMANT(x) > SPMANT(y)) + return x; + else + return y; +} + + +/* generate a normal/denormal number with over,under handeling + * sn is sign + * xe is an unbiased exponent + * xm is 3bit extended precision value. + */ +ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) +{ + assert(xm); /* we dont gen exact zeros (probably should) */ + + assert((xm >> (SP_MBITS + 1 + 3)) == 0); /* no execess */ + assert(xm & (SP_HIDDEN_BIT << 3)); + + if (xe < SP_EMIN) { + /* strip lower bits */ + int es = SP_EMIN - xe; + + if (ieee754_csr.nod) { + SETCX(IEEE754_UNDERFLOW); + return ieee754sp_zero(sn); + } + + /* sticky right shift es bits + */ + SPXSRSXn(es); + + assert((xm & (SP_HIDDEN_BIT << 3)) == 0); + assert(xe == SP_EMIN); + } + if (xm & (SP_MBIT(3) - 1)) { + SETCX(IEEE754_INEXACT); + /* inexact must round of 3 bits + */ + switch (ieee754_csr.rm) { + case IEEE754_RZ: + break; + case IEEE754_RN: + xm += 0x3 + ((xm >> 3) & 1); + /* xm += (xm&0x8)?0x4:0x3 */ + break; + case IEEE754_RU: /* toward +Infinity */ + if (!sn) /* ?? */ + xm += 0x8; + break; + case IEEE754_RD: /* toward -Infinity */ + if (sn) /* ?? */ + xm += 0x8; + break; + } + /* adjust exponent for rounding add overflowing + */ + if (xm >> (SP_MBITS + 1 + 3)) { /* add causes mantissa overflow */ + xm >>= 1; + xe++; + } + } + /* strip grs bits */ + xm >>= 3; + + assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ + assert(xe >= SP_EMIN); + + if (xe > SP_EMAX) { + SETCX(IEEE754_OVERFLOW); + /* -O can be table indexed by (rm,sn) */ + switch (ieee754_csr.rm) { + case IEEE754_RN: + return ieee754sp_inf(sn); + case IEEE754_RZ: + return ieee754sp_max(sn); + case IEEE754_RU: /* toward +Infinity */ + if (sn == 0) + return ieee754sp_inf(0); + else + return ieee754sp_max(1); + case IEEE754_RD: /* toward -Infinity */ + if (sn == 0) + return ieee754sp_max(0); + else + return ieee754sp_inf(1); + } + } + /* gen norm/denorm/zero */ + + if ((xm & SP_HIDDEN_BIT) == 0) { + /* we underflow (tiny/zero) */ + assert(xe == SP_EMIN); + SETCX(IEEE754_UNDERFLOW); + return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm); + } else { + assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ + assert(xm & SP_HIDDEN_BIT); + + return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); + } +} diff --git a/arch/mips64/math-emu/ieee754sp.h b/arch/mips64/math-emu/ieee754sp.h new file mode 100644 index 000000000000..b41b2a830f99 --- /dev/null +++ b/arch/mips64/math-emu/ieee754sp.h @@ -0,0 +1,89 @@ +/* + * IEEE754 floating point + * double precision internal header file + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754int.h" + +#define assert(expr) ((void)0) + +/* 3bit extended single precision sticky right shift */ +#define SPXSRSXn(rs) \ + (xe += rs, \ + xm = (rs > (SP_MBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0)) + +#define SPXSRSX1() \ + (xe++, (xm = (xm >> 1) | (xm & 1))) + +#define SPXSRSYn(rs) \ + (ye+=rs, \ + ym = (rs > (SP_MBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0)) + +#define SPXSRSY1() \ + (ye++, (ym = (ym >> 1) | (ym & 1))) + +/* convert denormal to normalized with extended exponent */ +#define SPDNORMx(m,e) \ + while( (m >> SP_MBITS) == 0) { m <<= 1; e--; } +#define SPDNORMX SPDNORMx(xm,xe) +#define SPDNORMY SPDNORMx(ym,ye) + +static __inline ieee754sp buildsp(int s, int bx, unsigned m) +{ + ieee754sp r; + + assert((s) == 0 || (s) == 1); + assert((bx) >= SP_EMIN - 1 + SP_EBIAS + && (bx) <= SP_EMAX + 1 + SP_EBIAS); + assert(((m) >> SP_MBITS) == 0); + + r.parts.sign = s; + r.parts.bexp = bx; + r.parts.mant = m; + + return r; +} + +extern int ieee754sp_isnan(ieee754sp); +extern int ieee754sp_issnan(ieee754sp); +extern int ieee754si_xcpt(int, const char *, ...); +extern long long ieee754di_xcpt(long long, const char *, ...); +extern ieee754sp ieee754sp_xcpt(ieee754sp, const char *, ...); +extern ieee754sp ieee754sp_nanxcpt(ieee754sp, const char *, ...); +extern ieee754sp ieee754sp_bestnan(ieee754sp, ieee754sp); +extern ieee754sp ieee754sp_format(int, int, unsigned); + + +#define SPNORMRET2(s,e,m,name,a0,a1) \ +{ \ + ieee754sp V = ieee754sp_format(s,e,m); \ + if(TSTX()) \ + return ieee754sp_xcpt(V,name,a0,a1); \ + else \ + return V; \ +} + +#define SPNORMRET1(s,e,m,name,a0) SPNORMRET2(s,e,m,name,a0,a0) diff --git a/arch/mips64/math-emu/ieee754xcpt.c b/arch/mips64/math-emu/ieee754xcpt.c new file mode 100644 index 000000000000..7a4d9486000a --- /dev/null +++ b/arch/mips64/math-emu/ieee754xcpt.c @@ -0,0 +1,48 @@ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + +/************************************************************************** + * Nov 7, 2000 + * Added preprocessor hacks to map to Linux kernel diagnostics. + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + *************************************************************************/ + +#include "ieee754.h" + +/* + * Very naff exception handler (you can plug in your own and + * override this). + */ + +static const char *const rtnames[] = { + "sp", "dp", "xp", "si", "di" +}; + +void ieee754_xcpt(struct ieee754xctx *xcp) +{ + printk("floating point exception in \"%s\", type=%s\n", + xcp->op, rtnames[xcp->rt]); +} + diff --git a/arch/mips64/math-emu/kernel_linkage.c b/arch/mips64/math-emu/kernel_linkage.c new file mode 100644 index 000000000000..c73c42c17d33 --- /dev/null +++ b/arch/mips64/math-emu/kernel_linkage.c @@ -0,0 +1,95 @@ +/************************************************************************** + * + * arch/mips/math_emu/kernel_linkage.c + * + * Kevin D. Kissell, kevink@mips and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + *************************************************************************/ +/* + * Routines corresponding to Linux kernel FP context + * manipulation primitives for the Algorithmics MIPS + * FPU Emulator + */ + +#include <linux/sched.h> +#include <asm/processor.h> +#include <asm/signal.h> +#include <asm/uaccess.h> + +#include <asm/fpu_emulator.h> + +extern struct mips_fpu_emulator_private fpuemuprivate; + +#define SIGNALLING_NAN 0x7ff800007ff80000LL + +void fpu_emulator_init_fpu(void) +{ + static int first = 1; + int i; + + if (first) { + first = 0; + printk("Algorithmics/MIPS FPU Emulator v1.4\n"); + } + + current->thread.fpu.soft.sr = 0; + for (i = 0; i < 32; i++) { + current->thread.fpu.soft.regs[i] = SIGNALLING_NAN; + } +} + + +/* + * Emulator context save/restore to/from a signal context + * presumed to be on the user stack, and therefore accessed + * with appropriate macros from uaccess.h + */ + +int fpu_emulator_save_context(struct sigcontext *sc) +{ + int i; + int err = 0; + + for (i = 0; i < 32; i++) { + err |= + __put_user(current->thread.fpu.soft.regs[i], + &sc->sc_fpregs[i]); + } + err |= __put_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr); + err |= __put_user(fpuemuprivate.eir, &sc->sc_fpc_eir); + + return err; +} + +int fpu_emulator_restore_context(struct sigcontext *sc) +{ + int i; + int err = 0; + + for (i = 0; i < 32; i++) { + err |= + __get_user(current->thread.fpu.soft.regs[i], + &sc->sc_fpregs[i]); + } + err |= __get_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr); + err |= __get_user(fpuemuprivate.eir, &sc->sc_fpc_eir); + + return err; +} + diff --git a/arch/mips64/math-emu/sp_add.c b/arch/mips64/math-emu/sp_add.c new file mode 100644 index 000000000000..61a050bf052d --- /dev/null +++ b/arch/mips64/math-emu/sp_add.c @@ -0,0 +1,180 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) +{ + COMPXSP; + COMPYSP; + + EXPLODEXSP; + EXPLODEYSP; + + CLEARCX; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "add", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y, "add", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x, "add", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754sp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Inifity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (xs == ys) + return x; + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "add", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + return y; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return x; + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + else + return ieee754sp_zero(ieee754_csr.rm == + IEEE754_RD); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return y; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + /* provide guard,round and stick bit space */ + xm <<= 3; + ym <<= 3; + + if (xe > ye) { + /* have to shift y fraction right to align + */ + int s = xe - ye; + SPXSRSYn(s); + } else if (ye > xe) { + /* have to shift x fraction right to align + */ + int s = ye - xe; + SPXSRSXn(s); + } + assert(xe == ye); + assert(xe <= SP_EMAX); + + if (xs == ys) { + /* generate 28 bit result of adding two 27 bit numbers + * leaving result in xm,xs,xe + */ + xm = xm + ym; + xe = xe; + xs = xs; + + if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */ + SPXSRSX1(); + } + } else { + if (xm >= ym) { + xm = xm - ym; + xe = xe; + xs = xs; + } else { + xm = ym - xm; + xe = xe; + xs = ys; + } + if (xm == 0) + return ieee754sp_zero(ieee754_csr.rm == + IEEE754_RD); + + /* normalize in extended single precision */ + while ((xm >> (SP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + + } + SPNORMRET2(xs, xe, xm, "add", x, y); +} diff --git a/arch/mips64/math-emu/sp_cmp.c b/arch/mips64/math-emu/sp_cmp.c new file mode 100644 index 000000000000..d8abc9c68c12 --- /dev/null +++ b/arch/mips64/math-emu/sp_cmp.c @@ -0,0 +1,58 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp) +{ + CLEARCX; + + if (ieee754sp_isnan(x) || ieee754sp_isnan(y)) { + if (cmp & IEEE754_CUN) + return 1; + if (cmp & (IEEE754_CLT | IEEE754_CGT)) { + if (SETCX(IEEE754_INVALID_OPERATION)) + return ieee754si_xcpt(0, "fcmpf", x); + } + return 0; + } else { + int vx = x.bits; + int vy = y.bits; + + if (vx < 0) + vx = -vx ^ SP_SIGN_BIT; + if (vy < 0) + vy = -vy ^ SP_SIGN_BIT; + + if (vx < vy) + return (cmp & IEEE754_CLT) != 0; + else if (vx == vy) + return (cmp & IEEE754_CEQ) != 0; + else + return (cmp & IEEE754_CGT) != 0; + } +} diff --git a/arch/mips64/math-emu/sp_div.c b/arch/mips64/math-emu/sp_div.c new file mode 100644 index 000000000000..14a87a5503a3 --- /dev/null +++ b/arch/mips64/math-emu/sp_div.c @@ -0,0 +1,160 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) +{ + COMPXSP; + COMPYSP; + + CLEARCX; + + EXPLODEXSP; + EXPLODEYSP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "div", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y, "div", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x, "div", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754sp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Infinity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + return ieee754sp_zero(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return ieee754sp_inf(xs ^ ys); + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + SETCX(IEEE754_ZERO_DIVIDE); + return ieee754sp_xcpt(ieee754sp_inf(xs ^ ys), "div", x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return ieee754sp_zero(xs == ys ? 0 : 1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + /* provide rounding space */ + xm <<= 3; + ym <<= 3; + + { + /* now the dirty work */ + + unsigned rm = 0; + int re = xe - ye; + unsigned bm; + + for (bm = SP_MBIT(SP_MBITS + 2); bm; bm >>= 1) { + if (xm >= ym) { + xm -= ym; + rm |= bm; + if (xm == 0) + break; + } + xm <<= 1; + } + rm <<= 1; + if (xm) + rm |= 1; /* have remainder, set sticky */ + + assert(rm); + + /* normalise rm to rounding precision ? + */ + while ((rm >> (SP_MBITS + 3)) == 0) { + rm <<= 1; + re--; + } + + SPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y); + } +} diff --git a/arch/mips64/math-emu/sp_fdp.c b/arch/mips64/math-emu/sp_fdp.c new file mode 100644 index 000000000000..a7ce2f0e05e5 --- /dev/null +++ b/arch/mips64/math-emu/sp_fdp.c @@ -0,0 +1,69 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_fdp(ieee754dp x) +{ + COMPXDP; + + CLEARCX; + + EXPLODEXDP; + + switch (xc) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + return ieee754sp_nanxcpt(buildsp(xs, + SP_EMAX + 1 + SP_EBIAS, + (unsigned long) + (xm >> + (DP_MBITS - SP_MBITS))), + "fdp", x); + case IEEE754_CLASS_INF: + return ieee754sp_inf(xs); + case IEEE754_CLASS_ZERO: + return ieee754sp_zero(xs); + case IEEE754_CLASS_DNORM: + /* cant possibly be sp representable */ + SETCX(IEEE754_UNDERFLOW); + return ieee754sp_xcpt(ieee754sp_zero(xs), "fdp", x); + case IEEE754_CLASS_NORM: + break; + } + + { + unsigned long rm; + + /* convert from DP_MBITS to SP_MBITS+3 with sticky right shift + */ + rm = (xm >> (DP_MBITS - (SP_MBITS + 3))) | + ((xm << (64 - (DP_MBITS - (SP_MBITS + 3)))) != 0); + + SPNORMRET1(xs, xe, rm, "fdp", x); + } +} diff --git a/arch/mips64/math-emu/sp_fint.c b/arch/mips64/math-emu/sp_fint.c new file mode 100644 index 000000000000..747fd86731de --- /dev/null +++ b/arch/mips64/math-emu/sp_fint.c @@ -0,0 +1,78 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_fint(int x) +{ + COMPXSP; + + CLEARCX; + + if (x == 0) + return ieee754sp_zero(0); + if (x == 1 || x == -1) + return ieee754sp_one(x < 0); + if (x == 10 || x == -10) + return ieee754sp_ten(x < 0); + + xs = (x < 0); + if (xs) { + if (x == (1 << 31)) + xm = ((unsigned) 1 << 31); /* max neg can't be safely negated */ + else + xm = -x; + } else { + xm = x; + } + xe = SP_MBITS + 3; + + if (xm >> (SP_MBITS + 1 + 3)) { + /* shunt out overflow bits + */ + while (xm >> (SP_MBITS + 1 + 3)) { + SPXSRSX1(); + } + } else { + /* normalize in grs extended single precision + */ + while ((xm >> (SP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + SPNORMRET1(xs, xe, xm, "fint", x); +} + + +ieee754sp ieee754sp_funs(unsigned int u) +{ + if ((int) u < 0) + return ieee754sp_add(ieee754sp_1e31(), + ieee754sp_fint(u & ~(1 << 31))); + return ieee754sp_fint(u); +} diff --git a/arch/mips64/math-emu/sp_flong.c b/arch/mips64/math-emu/sp_flong.c new file mode 100644 index 000000000000..6440572889c4 --- /dev/null +++ b/arch/mips64/math-emu/sp_flong.c @@ -0,0 +1,77 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_flong(long long x) +{ + COMPXDP; /* <--- need 64-bit mantissa temp */ + + CLEARCX; + + if (x == 0) + return ieee754sp_zero(0); + if (x == 1 || x == -1) + return ieee754sp_one(x < 0); + if (x == 10 || x == -10) + return ieee754sp_ten(x < 0); + + xs = (x < 0); + if (xs) { + if (x == (1ULL << 63)) + xm = (1ULL << 63); /* max neg can't be safely negated */ + else + xm = -x; + } else { + xm = x; + } + xe = SP_MBITS + 3; + + if (xm >> (SP_MBITS + 1 + 3)) { + /* shunt out overflow bits + */ + while (xm >> (SP_MBITS + 1 + 3)) { + SPXSRSX1(); + } + } else { + /* normalize in grs extended single precision */ + while ((xm >> (SP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + SPNORMRET1(xs, xe, xm, "sp_flong", x); +} + + +ieee754sp ieee754sp_fulong(unsigned long long u) +{ + if ((long long) u < 0) + return ieee754sp_add(ieee754sp_1e63(), + ieee754sp_flong(u & ~(1ULL << 63))); + return ieee754sp_flong(u); +} diff --git a/arch/mips64/math-emu/sp_frexp.c b/arch/mips64/math-emu/sp_frexp.c new file mode 100644 index 000000000000..968fe30cf5bf --- /dev/null +++ b/arch/mips64/math-emu/sp_frexp.c @@ -0,0 +1,53 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +/* close to ieeep754sp_logb +*/ +ieee754sp ieee754sp_frexp(ieee754sp x, int *eptr) +{ + COMPXSP; + CLEARCX; + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + *eptr = 0; + return x; + case IEEE754_CLASS_DNORM: + SPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + *eptr = xe + 1; + return buildsp(xs, -1 + SP_EBIAS, xm & ~SP_HIDDEN_BIT); +} diff --git a/arch/mips64/math-emu/sp_logb.c b/arch/mips64/math-emu/sp_logb.c new file mode 100644 index 000000000000..453f966dd74c --- /dev/null +++ b/arch/mips64/math-emu/sp_logb.c @@ -0,0 +1,54 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_logb(ieee754sp x) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + return ieee754sp_nanxcpt(x, "logb", x); + case IEEE754_CLASS_QNAN: + return x; + case IEEE754_CLASS_INF: + return ieee754sp_inf(0); + case IEEE754_CLASS_ZERO: + return ieee754sp_inf(1); + case IEEE754_CLASS_DNORM: + SPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + return ieee754sp_fint(xe); +} diff --git a/arch/mips64/math-emu/sp_modf.c b/arch/mips64/math-emu/sp_modf.c new file mode 100644 index 000000000000..69d69214899c --- /dev/null +++ b/arch/mips64/math-emu/sp_modf.c @@ -0,0 +1,80 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +/* modf function is always exact for a finite number +*/ +ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + *ip = x; + return x; + case IEEE754_CLASS_DNORM: + /* far to small */ + *ip = ieee754sp_zero(xs); + return x; + case IEEE754_CLASS_NORM: + break; + } + if (xe < 0) { + *ip = ieee754sp_zero(xs); + return x; + } + if (xe >= SP_MBITS) { + *ip = x; + return ieee754sp_zero(xs); + } + /* generate ipart mantissa by clearing bottom bits + */ + *ip = buildsp(xs, xe + SP_EBIAS, + ((xm >> (SP_MBITS - xe)) << (SP_MBITS - xe)) & + ~SP_HIDDEN_BIT); + + /* generate fpart mantissa by clearing top bits + * and normalizing (must be able to normalize) + */ + xm = (xm << (32 - (SP_MBITS - xe))) >> (32 - (SP_MBITS - xe)); + if (xm == 0) + return ieee754sp_zero(xs); + + while ((xm >> SP_MBITS) == 0) { + xm <<= 1; + xe--; + } + return buildsp(xs, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); +} diff --git a/arch/mips64/math-emu/sp_mul.c b/arch/mips64/math-emu/sp_mul.c new file mode 100644 index 000000000000..cecf18fd65ee --- /dev/null +++ b/arch/mips64/math-emu/sp_mul.c @@ -0,0 +1,174 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) +{ + COMPXSP; + COMPYSP; + + CLEARCX; + + EXPLODEXSP; + EXPLODEYSP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "mul", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y, "mul", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x, "mul", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754sp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Infinity handeling */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "mul", x, y); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + return ieee754sp_inf(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return ieee754sp_zero(xs ^ ys); + + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + /* rm = xm * ym, re = xe+ye basicly */ + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + { + int re = xe + ye; + int rs = xs ^ ys; + unsigned rm; + + /* shunt to top of word */ + xm <<= 32 - (SP_MBITS + 1); + ym <<= 32 - (SP_MBITS + 1); + + /* multiply 32bits xm,ym to give high 32bits rm with stickness + */ + { + unsigned short lxm = xm & 0xffff; + unsigned short hxm = xm >> 16; + unsigned short lym = ym & 0xffff; + unsigned short hym = ym >> 16; + unsigned lrm; + unsigned hrm; + + lrm = lxm * lym; /* 16 * 16 => 32 */ + hrm = hxm * hym; /* 16 * 16 => 32 */ + + { + unsigned t = lxm * hym; /* 16 * 16 => 32 */ + { + unsigned at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + } + hrm = hrm + (t >> 16); + } + + { + unsigned t = hxm * lym; /* 16 * 16 => 32 */ + { + unsigned at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + } + hrm = hrm + (t >> 16); + } + rm = hrm | (lrm != 0); + } + + /* + * sticky shift down to normal rounding precision + */ + if ((int) rm < 0) { + rm = (rm >> (32 - (SP_MBITS + 1 + 3))) | + ((rm << (SP_MBITS + 1 + 3)) != 0); + re++; + } else { + rm = (rm >> (32 - (SP_MBITS + 1 + 3 + 1))) | + ((rm << (SP_MBITS + 1 + 3 + 1)) != 0); + } + assert(rm & (SP_HIDDEN_BIT << 3)); + + SPNORMRET2(rs, re, rm, "mul", x, y); + } +} diff --git a/arch/mips64/math-emu/sp_scalb.c b/arch/mips64/math-emu/sp_scalb.c new file mode 100644 index 000000000000..65fdb51c5f40 --- /dev/null +++ b/arch/mips64/math-emu/sp_scalb.c @@ -0,0 +1,58 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_scalb(ieee754sp x, int n) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + return ieee754sp_nanxcpt(x, "scalb", x, n); + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_INF: + case IEEE754_CLASS_ZERO: + return x; + case IEEE754_CLASS_DNORM: + SPDNORMX; + break; + case IEEE754_CLASS_NORM: + break; + } + SPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n); +} + + +ieee754sp ieee754sp_ldexp(ieee754sp x, int n) +{ + return ieee754sp_scalb(x, n); +} diff --git a/arch/mips64/math-emu/sp_simple.c b/arch/mips64/math-emu/sp_simple.c new file mode 100644 index 000000000000..467e1065486b --- /dev/null +++ b/arch/mips64/math-emu/sp_simple.c @@ -0,0 +1,66 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +int ieee754sp_finite(ieee754sp x) +{ + return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS; +} + +ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y) +{ + CLEARCX; + SPSIGN(x) = SPSIGN(y); + return x; +} + + +ieee754sp ieee754sp_neg(ieee754sp x) +{ + CLEARCX; + + if (ieee754sp_isnan(x)) /* but not infinity */ + return ieee754sp_nanxcpt(x, "neg", x); + + /* quick fix up */ + SPSIGN(x) ^= 1; + return x; +} + + +ieee754sp ieee754sp_abs(ieee754sp x) +{ + CLEARCX; + + if (ieee754sp_isnan(x)) /* but not infinity */ + return ieee754sp_nanxcpt(x, "abs", x); + + /* quick fix up */ + SPSIGN(x) = 0; + return x; +} diff --git a/arch/mips64/math-emu/sp_sqrt.c b/arch/mips64/math-emu/sp_sqrt.c new file mode 100644 index 000000000000..d3eab4fb7a44 --- /dev/null +++ b/arch/mips64/math-emu/sp_sqrt.c @@ -0,0 +1,115 @@ +/* IEEE754 floating point arithmetic + * single precision square root + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +static const struct ieee754sp_konst knan = { + 0, SP_EBIAS + SP_EMAX + 1, 0 +}; + +#define nan ((ieee754sp)knan) + +ieee754sp ieee754sp_sqrt(ieee754sp x) +{ + int sign = (int) 0x80000000; + int ix, s, q, m, t, i; + unsigned int r; + COMPXDP; + + /* take care of Inf and NaN */ + + EXPLODEXDP; + + /* x == INF or NAN? */ + switch (xc) { + case IEEE754_CLASS_QNAN: + case IEEE754_CLASS_SNAN: + /* sqrt(Nan) = Nan */ + return ieee754sp_nanxcpt(x, "sqrt"); + case IEEE754_CLASS_ZERO: + /* sqrt(0) = 0 */ + return x; + case IEEE754_CLASS_INF: + if (xs) + /* sqrt(-Inf) = Nan */ + return ieee754sp_nanxcpt(nan, "sqrt"); + /* sqrt(+Inf) = Inf */ + return x; + case IEEE754_CLASS_DNORM: + case IEEE754_CLASS_NORM: + if (xs) + /* sqrt(-x) = Nan */ + return ieee754sp_nanxcpt(nan, "sqrt"); + break; + } + + ix = x.bits; + + /* normalize x */ + m = (ix >> 23); + if (m == 0) { /* subnormal x */ + for (i = 0; (ix & 0x00800000) == 0; i++) + ix <<= 1; + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if (m & 1) /* odd m, double x to make it even */ + ix += ix; + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = s = 0; /* q = sqrt(x) */ + r = 0x01000000; /* r = moving bit from right to left */ + + while (r != 0) { + t = s + r; + if (t <= ix) { + s = t + r; + ix -= t; + q += r; + } + ix += ix; + r >>= 1; + } + + if (ix != 0) { + switch (ieee754_csr.rm) { + case IEEE754_RP: + q += 2; + break; + case IEEE754_RN: + q += (q & 1); + break; + } + } + ix = (q >> 1) + 0x3f000000; + ix += (m << 23); + x.bits = ix; + return x; +} diff --git a/arch/mips64/math-emu/sp_sub.c b/arch/mips64/math-emu/sp_sub.c new file mode 100644 index 000000000000..c28fc89351a3 --- /dev/null +++ b/arch/mips64/math-emu/sp_sub.c @@ -0,0 +1,187 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) +{ + COMPXSP; + COMPYSP; + + CLEARCX; + + EXPLODEXSP; + EXPLODEYSP; + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "sub", x, + y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y, "sub", x, y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x, "sub", x, y); + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return ieee754sp_bestnan(x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* Inifity handeling + */ + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (xs != ys) + return x; + SETCX(IEEE754_INVALID_OPERATION); + return ieee754sp_xcpt(ieee754sp_indef(), "sub", x, y); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + return ieee754sp_inf(ys ^ 1); + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + return x; + + /* Zero handeling + */ + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs != ys) + return x; + else + return ieee754sp_zero(ieee754_csr.rm == + IEEE754_RD); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + /* quick fix up */ + DPSIGN(y) ^= 1; + return y; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + break; + } + /* flip sign of y and handle as add */ + ys ^= 1; + + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + + /* provide guard,round and stick bit space */ + xm <<= 3; + ym <<= 3; + + if (xe > ye) { + /* have to shift y fraction right to align + */ + int s = xe - ye; + SPXSRSYn(s); + } else if (ye > xe) { + /* have to shift x fraction right to align + */ + int s = ye - xe; + SPXSRSXn(s); + } + assert(xe == ye); + assert(xe <= SP_EMAX); + + if (xs == ys) { + /* generate 28 bit result of adding two 27 bit numbers + */ + xm = xm + ym; + xe = xe; + xs = xs; + + if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */ + SPXSRSX1(); /* shift preserving sticky */ + } + } else { + if (xm >= ym) { + xm = xm - ym; + xe = xe; + xs = xs; + } else { + xm = ym - xm; + xe = xe; + xs = ys; + } + if (xm == 0) + if (ieee754_csr.rm == IEEE754_RD) + return ieee754sp_zero(1); /* round negative inf. => sign = -1 */ + else + return ieee754sp_zero(0); /* other round modes => sign = 1 */ + + /* normalize to rounding precision + */ + while ((xm >> (SP_MBITS + 3)) == 0) { + xm <<= 1; + xe--; + } + } + SPNORMRET2(xs, xe, xm, "sub", x, y); +} diff --git a/arch/mips64/math-emu/sp_tint.c b/arch/mips64/math-emu/sp_tint.c new file mode 100644 index 000000000000..8f3ed14c6090 --- /dev/null +++ b/arch/mips64/math-emu/sp_tint.c @@ -0,0 +1,88 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include <linux/kernel.h> +#include "ieee754sp.h" + +int ieee754sp_tint(ieee754sp x) +{ + COMPXSP; + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754si_xcpt(ieee754si_indef(), "fixsp", x); + case IEEE754_CLASS_INF: + SETCX(IEEE754_OVERFLOW); + return ieee754si_xcpt(ieee754si_indef(), "fixsp", x); + case IEEE754_CLASS_ZERO: + return 0; + case IEEE754_CLASS_DNORM: /* much to small */ + SETCX(IEEE754_UNDERFLOW); + return ieee754si_xcpt(0, "fixsp", x); + case IEEE754_CLASS_NORM: + break; + } + if (xe >= 31) { + SETCX(IEEE754_OVERFLOW); + return ieee754si_xcpt(ieee754si_indef(), "fix", x); + } + if (xe < 0) { + SETCX(IEEE754_UNDERFLOW); + return ieee754si_xcpt(0, "fix", x); + } + /* oh gawd */ + if (xe > SP_MBITS) { + xm <<= xe - SP_MBITS; + } else if (xe < SP_MBITS) { + /* XXX no rounding + */ + xm >>= SP_MBITS - xe; + } + if (xs) + return -xm; + else + return xm; +} + + +unsigned int ieee754sp_tuns(ieee754sp x) +{ + ieee754sp hb = ieee754sp_1e31(); + + /* what if x < 0 ?? */ + if (ieee754sp_lt(x, hb)) + return (unsigned) ieee754sp_tint(x); + + return (unsigned) ieee754sp_tint(ieee754sp_sub(x, hb)) | + ((unsigned) 1 << 31); +} diff --git a/arch/mips64/math-emu/sp_tlong.c b/arch/mips64/math-emu/sp_tlong.c new file mode 100644 index 000000000000..a7b0712e32f5 --- /dev/null +++ b/arch/mips64/math-emu/sp_tlong.c @@ -0,0 +1,87 @@ +/* IEEE754 floating point arithmetic + * single precision + */ +/* + * MIPS floating point support + * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved. + * http://www.algor.co.uk + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + */ + + +#include "ieee754sp.h" + +long long ieee754sp_tlong(ieee754sp x) +{ + COMPXDP; /* <-- need 64-bit mantissa tmp */ + + CLEARCX; + + EXPLODEXSP; + + switch (xc) { + case IEEE754_CLASS_SNAN: + case IEEE754_CLASS_QNAN: + SETCX(IEEE754_INVALID_OPERATION); + return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); + case IEEE754_CLASS_INF: + SETCX(IEEE754_OVERFLOW); + return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); + case IEEE754_CLASS_ZERO: + return 0; + case IEEE754_CLASS_DNORM: /* much to small */ + SETCX(IEEE754_UNDERFLOW); + return ieee754di_xcpt(0, "sp_tlong", x); + case IEEE754_CLASS_NORM: + break; + } + if (xe >= 63) { + SETCX(IEEE754_OVERFLOW); + return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); + } + if (xe < 0) { + SETCX(IEEE754_UNDERFLOW); + return ieee754di_xcpt(0, "sp_tlong", x); + } + /* oh gawd */ + if (xe > SP_MBITS) { + xm <<= xe - SP_MBITS; + } else if (xe < SP_MBITS) { + /* XXX no rounding + */ + xm >>= SP_MBITS - xe; + } + if (xs) + return -xm; + else + return xm; +} + + +unsigned long long ieee754sp_tulong(ieee754sp x) +{ + ieee754sp hb = ieee754sp_1e63(); + + /* what if x < 0 ?? */ + if (ieee754sp_lt(x, hb)) + return (unsigned long long) ieee754sp_tlong(x); + + return (unsigned long long) ieee754sp_tlong(ieee754sp_sub(x, hb)) | + (1ULL << 63); +} diff --git a/arch/parisc/vmlinux.lds b/arch/parisc/vmlinux.lds index 268fc59ce865..b06a86f16716 100644 --- a/arch/parisc/vmlinux.lds +++ b/arch/parisc/vmlinux.lds @@ -22,7 +22,7 @@ SECTIONS } = 0 . = ALIGN(16); - .rodata : { *(.rodata) } + .rodata : { *(.rodata) *(.rodata.*) } .kstrtab : { *(.kstrtab) } _etext = .; /* End of text section */ diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c index 71351de4f2c3..2e27a6e26c19 100644 --- a/arch/ppc/8xx_io/commproc.c +++ b/arch/ppc/8xx_io/commproc.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.commproc.c 1.8 05/18/01 07:54:04 patch + * BK Id: SCCS/s.commproc.c 1.11 06/15/01 13:00:20 paulus */ /* @@ -47,12 +47,12 @@ cpm8xx_t *cpmp; /* Pointer to comm processor space */ /* CPM interrupt vector functions. */ struct cpm_action { - void (*handler)(void *); + void (*handler)(void *, struct pt_regs * regs); void *dev_id; }; static struct cpm_action cpm_vecs[CPMVEC_NR]; static void cpm_interrupt(int irq, void * dev, struct pt_regs * regs); -static void cpm_error_interrupt(void *); +static void cpm_error_interrupt(void *, struct pt_regs * regs); void m8xx_cpm_reset(uint host_page_addr) @@ -129,7 +129,7 @@ cpm_interrupt(int irq, void * dev, struct pt_regs * regs) vec >>= 11; if (cpm_vecs[vec].handler != 0) - (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id); + (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id, regs); else ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); @@ -146,14 +146,15 @@ cpm_interrupt(int irq, void * dev, struct pt_regs * regs) * tests in the interrupt handler. */ static void -cpm_error_interrupt(void *dev) +cpm_error_interrupt(void *dev, struct pt_regs *regs) { } /* Install a CPM interrupt handler. */ void -cpm_install_handler(int vec, void (*handler)(void *), void *dev_id) +cpm_install_handler(int vec, void (*handler)(void *, struct pt_regs *regs), + void *dev_id) { /* If null handler, assume we are trying to free the IRQ. diff --git a/arch/ppc/8xx_io/commproc.h b/arch/ppc/8xx_io/commproc.h index 290dba0470ae..5ed4f2a100ed 100644 --- a/arch/ppc/8xx_io/commproc.h +++ b/arch/ppc/8xx_io/commproc.h @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.commproc.h 1.8 05/17/01 18:14:20 cort + * BK Id: SCCS/s.commproc.h 1.13 06/15/01 13:00:20 paulus */ /* @@ -789,7 +789,8 @@ typedef struct iic { #define CICR_IEN ((uint)0x00000080) /* Int. enable */ #define CICR_SPS ((uint)0x00000001) /* SCC Spread */ -extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id); +extern void cpm_install_handler(int vec, + void (*handler)(void *, struct pt_regs *regs), void *dev_id); extern void cpm_free_handler(int vec); #endif /* __CPM_8XX__ */ diff --git a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c index 328a2a550e9b..55d2be35014c 100644 --- a/arch/ppc/8xx_io/uart.c +++ b/arch/ppc/8xx_io/uart.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.uart.c 1.10 05/17/01 18:14:20 cort + * BK Id: SCCS/s.uart.c 1.14 06/27/01 14:49:55 trini */ /* * UART driver for MPC860 CPM SCC or SMC @@ -44,6 +44,9 @@ #include <asm/8xx_immap.h> #include <asm/mpc8xx.h> #include "commproc.h" +#ifdef CONFIG_MAGIC_SYSRQ +#include <linux/sysrq.h> +#endif #ifdef CONFIG_KGDB extern void breakpoint(void); @@ -91,6 +94,15 @@ static struct tty_driver serial_driver, callout_driver; static int serial_refcount; static int serial_console_setup(struct console *co, char *options); +static int serial_console_wait_key(struct console *co); +static void serial_console_write(struct console *c, const char *s, + unsigned count); +static kdev_t serial_console_device(struct console *c); + +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +static unsigned long break_pressed; /* break, really ... */ +#endif + /* * Serial driver configuration section. Here are the various options: */ @@ -202,6 +214,16 @@ typedef struct serial_info { cbd_t *tx_cur; } ser_info_t; +static struct console sercons = { + name: "ttyS", + write: serial_console_write, + device: serial_console_device, + wait_key: serial_console_wait_key, + setup: serial_console_setup, + flags: CON_PRINTBUFFER, + index: CONFIG_SERIAL_CONSOLE_PORT, +}; + static void change_speed(ser_info_t *info); static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout); @@ -325,7 +347,7 @@ static _INLINE_ void rs_sched_event(ser_info_t *info, mark_bh(SERIAL_BH); } -static _INLINE_ void receive_chars(ser_info_t *info) +static _INLINE_ void receive_chars(ser_info_t *info, struct pt_regs *regs) { struct tty_struct *tty = info->tty; unsigned char ch, *cp; @@ -413,7 +435,7 @@ static _INLINE_ void receive_chars(ser_info_t *info) } */ status &= info->read_status_mask; - + if (status & (BD_SC_BR)) { #ifdef SERIAL_DEBUG_INTR printk("handling break...."); @@ -440,6 +462,17 @@ static _INLINE_ void receive_chars(ser_info_t *info) } } } +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) + if (break_pressed && info->line == sercons.index) { + if (ch != 0 && time_before(jiffies, + break_pressed + HZ*5)) { + handle_sysrq(ch, regs, NULL, NULL); + break_pressed = 0; + goto ignore_char; + } else + break_pressed = 0; + } +#endif if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; @@ -448,6 +481,7 @@ static _INLINE_ void receive_chars(ser_info_t *info) tty->flip.count++; } + ignore_char: /* This BD is ready to be used again. Clear status. * Get next BD. */ @@ -459,17 +493,27 @@ static _INLINE_ void receive_chars(ser_info_t *info) else bdp++; } - info->rx_cur = (cbd_t *)bdp; queue_task(&tty->flip.tqueue, &tq_timer); } -static _INLINE_ void receive_break(ser_info_t *info) +static _INLINE_ void receive_break(ser_info_t *info, struct pt_regs *regs) { struct tty_struct *tty = info->tty; info->state->icount.brk++; + +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) + if (info->line == sercons.index) { + if (!break_pressed) { + break_pressed = jiffies; + return; + } else + break_pressed = 0; + } +#endif + /* Check to see if there is room in the tty buffer for * the break. If not, we exit now, losing the break. FIXME */ @@ -482,7 +526,7 @@ static _INLINE_ void receive_break(ser_info_t *info) queue_task(&tty->flip.tqueue, &tq_timer); } -static _INLINE_ void transmit_chars(ser_info_t *info) +static _INLINE_ void transmit_chars(ser_info_t *info, struct pt_regs *regs) { if ((info->flags & TX_WAKEUP) || @@ -571,7 +615,7 @@ static _INLINE_ void check_modem_status(struct async_struct *info) /* * This is the serial driver's interrupt routine for a single port */ -static void rs_8xx_interrupt(void *dev_id) +static void rs_8xx_interrupt(void *dev_id, struct pt_regs *regs) { u_char events; int idx; @@ -585,21 +629,23 @@ static void rs_8xx_interrupt(void *dev_id) if (info->state->smc_scc_num & NUM_IS_SCC) { sccp = &cpmp->cp_scc[idx]; events = sccp->scc_scce; + if (events & SMCM_BRKE) + receive_break(info, regs); if (events & SCCM_RX) - receive_chars(info); + receive_chars(info, regs); if (events & SCCM_TX) - transmit_chars(info); + transmit_chars(info, regs); sccp->scc_scce = events; } else { smcp = &cpmp->cp_smc[idx]; events = smcp->smc_smce; if (events & SMCM_BRKE) - receive_break(info); + receive_break(info, regs); if (events & SMCM_RX) - receive_chars(info); + receive_chars(info, regs); if (events & SMCM_TX) - transmit_chars(info); + transmit_chars(info, regs); smcp->smc_smce = events; } @@ -2428,17 +2474,6 @@ static kdev_t serial_console_device(struct console *c) return MKDEV(TTY_MAJOR, 64 + c->index); } - -static struct console sercons = { - name: "ttyS", - write: serial_console_write, - device: serial_console_device, - wait_key: serial_console_wait_key, - setup: serial_console_setup, - flags: CON_PRINTBUFFER, - index: CONFIG_SERIAL_CONSOLE_PORT, -}; - /* * Register console. */ @@ -2771,7 +2806,7 @@ int __init rs_8xx_init(void) immap->im_ioport.iop_padir &= ~iobits; immap->im_ioport.iop_paodr &= ~iobits; } -#endif +#endif /* CONFIG_ALTSMC2 */ /* Connect the baud rate generator to the * SMC based upon index in rs_table. Also diff --git a/arch/ppc/boot/chrp/main.c b/arch/ppc/boot/chrp/main.c index 14c4ff6f4274..159ffe7fecc4 100644 --- a/arch/ppc/boot/chrp/main.c +++ b/arch/ppc/boot/chrp/main.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.main.c 1.7 05/18/01 06:20:29 patch + * BK Id: SCCS/s.main.c 1.9 06/12/01 16:42:26 paulus */ /* * Copyright (C) Paul Mackerras 1997. @@ -100,13 +100,13 @@ chrpboot(int a1, int a2, void *prom) rec->tag = BI_MACHTYPE; rec->data[0] = _MACH_chrp; rec->data[1] = 1; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long); rec = (struct bi_record *)((unsigned long)rec + rec->size); #if 0 rec->tag = BI_SYSMAP; rec->data[0] = (unsigned long)sysmap_data; rec->data[1] = sysmap_len; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long); rec = (struct bi_record *)((unsigned long)rec + rec->size); #endif rec->tag = BI_LAST; diff --git a/arch/ppc/boot/common/misc-common.c b/arch/ppc/boot/common/misc-common.c index bb5fe419f60a..77a9a1ba5fbe 100644 --- a/arch/ppc/boot/common/misc-common.c +++ b/arch/ppc/boot/common/misc-common.c @@ -38,7 +38,7 @@ /* If we're on a ALL_PPC, assume we have a keyboard controller * Also note, if we're not ALL_PPC, we assume you are a serial * console - Tom */ -#ifdef CONFIG_ALL_PPC +#if defined(CONFIG_ALL_PPC) && defined(CONFIG_VGA_CONSOLE) extern void cursor(int x, int y); extern void scroll(void); extern char *vidmem; diff --git a/arch/ppc/boot/pmac/chrpmain.c b/arch/ppc/boot/pmac/chrpmain.c index 67d53a7891db..96ee2ace16cb 100644 --- a/arch/ppc/boot/pmac/chrpmain.c +++ b/arch/ppc/boot/pmac/chrpmain.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.chrpmain.c 1.9 05/18/01 06:20:29 patch + * BK Id: SCCS/s.chrpmain.c 1.12 06/12/01 16:42:26 paulus */ /* * Copyright (C) Paul Mackerras 1997. @@ -34,15 +34,6 @@ void stop_imac_usb(void); #define SCRATCH_SIZE (128 << 10) -#ifdef CONFIG_CMDLINE -#define CMDLINE CONFIG_CMDLINE -#else -#define CMDLINE "" -#endif -char cmd_preset[] = CMDLINE; -char cmd_buf[256]; -char *cmd_line = cmd_buf; - char *avail_ram; char *begin_avail, *end_avail; char *avail_high; @@ -98,7 +89,6 @@ boot(int a1, int a2, void *prom) } flush_cache(dst, len); - memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); make_bi_recs((unsigned long) dst + len); sa = (unsigned long)PROG_START; @@ -133,19 +123,14 @@ void make_bi_recs(unsigned long addr) rec->tag = BI_MACHTYPE; rec->data[0] = _MACH_Pmac; rec->data[1] = 1; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_CMD_LINE; - memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); - rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; + rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long); rec = (struct bi_record *)((unsigned long)rec + rec->size); #ifdef SYSMAP_OFFSET rec->tag = BI_SYSMAP; rec->data[0] = SYSMAP_OFFSET; rec->data[1] = SYSMAP_SIZE; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long); rec = (struct bi_record *)((unsigned long)rec + rec->size); #endif /* SYSMAP_OFFSET */ diff --git a/arch/ppc/boot/pmac/coffmain.c b/arch/ppc/boot/pmac/coffmain.c index 025123c38caf..28111b1a0242 100644 --- a/arch/ppc/boot/pmac/coffmain.c +++ b/arch/ppc/boot/pmac/coffmain.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.coffmain.c 1.9 05/18/01 06:20:29 patch + * BK Id: SCCS/s.coffmain.c 1.12 06/12/01 16:42:26 paulus */ /* * Copyright (C) Paul Mackerras 1997. @@ -24,7 +24,7 @@ void gunzip(void *, int, unsigned char *, int *); #define get_16be(x) (*(unsigned short *)(x)) #define get_32be(x) (*(unsigned *)(x)) -#define RAM_START 0xc0000000 +#define RAM_START 0 #define RAM_END (RAM_START + 0x800000) /* only 8M mapped with BATs */ #define PROG_START RAM_START @@ -32,15 +32,6 @@ void gunzip(void *, int, unsigned char *, int *); #define SCRATCH_SIZE (128 << 10) -#ifdef CONFIG_CMDLINE -#define CMDLINE CONFIG_CMDLINE -#else -#define CMDLINE "" -#endif -char cmd_preset[] = CMDLINE; -char cmd_buf[256]; -char *cmd_line = cmd_buf; - char *avail_ram; char *begin_avail, *end_avail; char *avail_high; @@ -81,7 +72,7 @@ boot(int a1, int a2, void *prom) claim(0, PROG_SIZE, 0); dst = (void *) RAM_START; if (im[0] == 0x1f && im[1] == 0x8b) { - /* claim some memory for scratch space */ + /* set up scratch space */ begin_avail = avail_high = avail_ram = heap; end_avail = heap + sizeof(heap); printf("heap at 0x%x\n", avail_ram); @@ -95,7 +86,6 @@ boot(int a1, int a2, void *prom) } flush_cache(dst, len); - memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); make_bi_recs((unsigned long)dst + len); sa = (unsigned long)PROG_START; @@ -127,18 +117,13 @@ void make_bi_recs(unsigned long addr) sprintf( (char *)rec->data, "coffboot"); rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1; rec = (struct bi_record *)((unsigned long)rec + rec->size); - + rec->tag = BI_MACHTYPE; rec->data[0] = _MACH_Pmac; rec->data[1] = 1; - rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long); rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_CMD_LINE; - memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1); - rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1; - rec = (struct bi_record *)((unsigned long)rec + rec->size); - + rec->tag = BI_LAST; rec->size = sizeof(struct bi_record); rec = (struct bi_record *)((unsigned long)rec + rec->size); diff --git a/arch/ppc/boot/pmac/ld.script b/arch/ppc/boot/pmac/ld.script index 2469ed65dcb3..33317e773e22 100644 --- a/arch/ppc/boot/pmac/ld.script +++ b/arch/ppc/boot/pmac/ld.script @@ -32,6 +32,7 @@ SECTIONS { *(.text) *(.rodata) + *(.rodata.*) *(.rodata1) *(.got1) } diff --git a/arch/ppc/boot/prep/Makefile b/arch/ppc/boot/prep/Makefile index d2a08340e9a7..11c485a44e2d 100644 --- a/arch/ppc/boot/prep/Makefile +++ b/arch/ppc/boot/prep/Makefile @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.15 05/21/01 11:51:32 trini +# BK Id: SCCS/s.Makefile 1.17 06/12/01 16:47:44 paulus # # arch/ppc/boot/Makefile # @@ -33,7 +33,7 @@ TFTPIMAGE=/tftpboot/zImage.prep endif ZLINKFLAGS = -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds -Ttext 0x00800000 -OBJECTS := head.o misc.o vreset.o kbd.o ../common/misc-common.o \ +OBJECTS := head.o misc.o ../common/misc-common.o \ ../common/string.o of1275.o OBJCOPY_ARGS = -O elf32-powerpc LIBS = ../lib/zlib.a @@ -42,6 +42,10 @@ ifeq ($(CONFIG_SERIAL_CONSOLE),y) OBJECTS += ns16550.o endif +ifeq ($(CONFIG_VGA_CONSOLE),y) +OBJECTS += vreset.o kbd.o +endif + # Tools MKPREP := ../utils/mkprep SIZE := ../utils/size diff --git a/arch/ppc/boot/prep/misc.c b/arch/ppc/boot/prep/misc.c index e1c07ca006d8..1aaac8c2e7a2 100644 --- a/arch/ppc/boot/prep/misc.c +++ b/arch/ppc/boot/prep/misc.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.misc.c 1.10 06/05/01 20:20:05 paulus + * BK Id: SCCS/s.misc.c 1.14 06/16/01 20:43:20 trini */ /* * misc.c @@ -13,8 +13,9 @@ #include <linux/types.h> #include "zlib.h" #include <asm/residual.h> -#include <linux/elf.h> #include <linux/config.h> +#include <linux/threads.h> +#include <linux/elf.h> #include <linux/pci_ids.h> #include <asm/page.h> #include <asm/processor.h> @@ -102,6 +103,7 @@ pci_read_config_32(unsigned char devfn, return; } +#ifdef CONFIG_VGA_CONSOLE void scroll() { @@ -111,6 +113,7 @@ scroll() for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 ) vidmem[i] = ' '; } +#endif /* CONFIG_VGA_CONSOLE */ /* * This routine is used to control the second processor on the @@ -170,7 +173,9 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, #if defined(CONFIG_SERIAL_CONSOLE) com_port = serial_init(0); #endif /* CONFIG_SERIAL_CONSOLE */ - vga_init((char)0xC0000000); +#if defined(CONFIG_VGA_CONSOLE) + vga_init((unsigned char *)0xC0000000); +#endif /* CONFIG_VGA_CONSOLE */ if (residual) { @@ -360,11 +365,18 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, while (timer++ < 5*1000) { if (tstc()) { while ((ch = getc()) != '\n' && ch != '\r') { - if (ch == '\b') { + /* Test for backspace/delete */ + if (ch == '\b' || ch == '\177') { if (cp != cmd_line) { cp--; puts("\b \b"); } + /* Test for ^x/^u (and wipe the line) */ + } else if (ch == '\030' || ch == '\025') { + while (cp != cmd_line) { + cp--; + puts("\b \b"); + } } else { *cp++ = ch; putc(ch); diff --git a/arch/ppc/boot/tree/Makefile b/arch/ppc/boot/tree/Makefile index 309616eac225..6f2498334a00 100644 --- a/arch/ppc/boot/tree/Makefile +++ b/arch/ppc/boot/tree/Makefile @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.5 05/18/01 06:20:29 patch +# BK Id: SCCS/s.Makefile 1.7 06/15/01 13:16:10 paulus # # # Module name: Makefile @@ -26,12 +26,13 @@ OBJDUMP = $(CROSS_COMPILE)objdump GZIP = gzip -vf9 RM = rm -f -MKEVIMG = ../utils/mkevimg -l +MKEVIMG = ../utils/mkevimg -l -c MKIRIMG = ../utils/mkirimg +CFLAGS += -I$(TOPDIR)/drivers/net LD_ARGS = -e _start -T ld.script -Ttext 0x00200000 -Bstatic OBJS = ../common/crt0.o main.o misc.o irSect.o ../common/string.o \ - ../common/misc-common.o + ../common/misc-common.o ../common/ns16550.o LIBS = ../lib/zlib.a treeboot: $(OBJS) $(LIBS) ld.script diff --git a/arch/ppc/boot/tree/ld.script b/arch/ppc/boot/tree/ld.script index 2469ed65dcb3..33317e773e22 100644 --- a/arch/ppc/boot/tree/ld.script +++ b/arch/ppc/boot/tree/ld.script @@ -32,6 +32,7 @@ SECTIONS { *(.text) *(.rodata) + *(.rodata.*) *(.rodata1) *(.got1) } diff --git a/arch/ppc/boot/tree/main.c b/arch/ppc/boot/tree/main.c index 367aca873cdb..f97e858011a2 100644 --- a/arch/ppc/boot/tree/main.c +++ b/arch/ppc/boot/tree/main.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.main.c 1.7 05/18/01 06:20:29 patch + * BK Id: SCCS/s.main.c 1.9 06/15/01 13:16:10 paulus */ /* * Copyright (c) 1997 Paul Mackerras <paulus@cs.anu.edu.au> @@ -74,16 +74,6 @@ #define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) -#define stringify(s) tostring(s) -#define tostring(s) #s - -#define mtdcr(rn, v) asm volatile("mtdcr " stringify(rn) ",%0" : : "r" (v)) -#define mfdcr(rn) ({unsigned int rval; \ - asm volatile("mfdcr %0," stringify(rn) \ - : "=r" (rval)); rval;}) -#define DCRN_MALCR 0x180 /* MAL Configuration */ -#define MALCR_SR 0x80000000 /* Software Reset */ - /* Global Variables */ /* Needed by zalloc and zfree for allocating memory */ @@ -91,15 +81,11 @@ char *avail_ram; /* Indicates start of RAM available for heap */ char *end_avail; /* Indicates end of RAM available for heap */ -bd_t board_info; - -/* - * XXX - Until either the IBM boot ROM provides a way of passing arguments to - * the program it launches or until I/O is working in the boot loader, - * this is a good spot to pass in command line arguments to the kernel - * (e.g. console=tty0). - */ +/* Needed for serial I/O. +*/ +extern unsigned long *com_port; +bd_t board_info; /* ** The bootrom may change bootrom_cmdline to point to a buffer in the @@ -116,35 +102,16 @@ char *cmdline = ""; /* Function Prototypes */ -extern void *zalloc(void *x, unsigned items, unsigned size); - -/* serial I/O functions. - * These should have generic names, although this is similar to 16550.... - */ -static volatile unsigned char *uart0_lsr = (unsigned char *)0xef600305; -static volatile unsigned char *uart0_xcvr = (unsigned char *)0xef600300; +extern void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp); void -serial_putc(void *unused, unsigned char c) -{ - while ((*uart0_lsr & LSR_THRE) == 0); - *uart0_xcvr = c; -} - -unsigned char -serial_getc(void *unused) +kick_watchdog(void) { - while ((*uart0_lsr & LSR_DR) == 0); - return (*uart0_xcvr); -} - -int -serial_tstc(void *unused) -{ - return ((*uart0_lsr & LSR_DR) != 0); +#ifdef CONFIG_405GP + mtspr(SPRN_TSR, (TSR_ENW | TSR_WIS)); +#endif } - void start(void) { void *options; @@ -156,40 +123,34 @@ void start(void) bd_t *(*get_board_info)(void) = (bd_t *(*)(void))(*(unsigned long *)BOARD_INFO_VECTOR); bd_t *bip = NULL; - volatile unsigned long *em0mr0 = (long *)0xEF600800; /* ftr fixup */ + com_port = (struct NS16550 *)serial_init(0); -#if defined(CONFIG_WALNUT) - /* turn off ethernet */ +#ifdef CONFIG_405GP + /* turn off on-chip ethernet */ /* This is to fix a problem with early walnut bootrom. */ + + { + /* Physical mapping of ethernet register space. */ + static struct ppc405_enet_regs *ppc405_enet_regp = + (struct ppc405_enet_regs *)PPC405_EM0_REG_ADDR; - mtdcr(DCRN_MALCR, MALCR_SR); /* 1st reset MAL */ - - while (mfdcr(DCRN_MALCR) & MALCR_SR) {}; /* wait for the reset */ + mtdcr(DCRN_MALCR, MALCR_MMSR); /* 1st reset MAL */ - *em0mr0 = 0x20000000; /* then reset EMAC */ -#endif - - -#if 0 - /* ftr revisit - remove printf()s */ - - printf("\n\nbootrom_cmdline = >%s<\n\n", bootrom_cmdline); - if (*bootrom_cmdline != '\0') { - printf("bootrom_cmdline != NULL, copying it into cmdline\n\n"); - *treeboot_bootrom_cmdline = '\0'; - strcat(treeboot_bootrom_cmdline, bootrom_cmdline); - cmdline = treeboot_bootrom_cmdline; + while (mfdcr(DCRN_MALCR) & MALCR_MMSR) {}; /* wait for the reset */ + + ppc405_enet_regp->em0mr0 = 0x20000000; /* then reset EMAC */ } #endif - if ((bip = get_board_info()) != NULL) memcpy(&board_info, bip, sizeof(bd_t)); /* Init RAM disk (initrd) section */ + kick_watchdog(); + if (initrdSect_start != 0 && (initrd_size = initrdSect_size) != 0) { initrd_start = (RAM_END - initrd_size) & ~0xFFF; @@ -208,6 +169,8 @@ void start(void) /* Linux kernel image section */ + kick_watchdog(); + im = (unsigned char *)(imageSect_start); len = imageSect_size; dst = (void *)PROG_START; @@ -233,6 +196,7 @@ void start(void) memmove(dst, im, len); } + kick_watchdog(); flush_cache(dst, len); diff --git a/arch/ppc/boot/utils/mkevimg b/arch/ppc/boot/utils/mkevimg index 195fd37d4916..589b18ebc663 100644 --- a/arch/ppc/boot/utils/mkevimg +++ b/arch/ppc/boot/utils/mkevimg @@ -23,7 +23,8 @@ # unsigned long num_512blocks; Size, rounded-up, in 512 byte blocks # unsigned long debug_flag; Run the debugger or image after load # unsigned long entry_point; The image address to jump to after load -# unsigned long reserved[3]; +# unsigned long checksum; 32 bit checksum including header +# unsigned long reserved[2]; # } boot_block_t; # # @@ -61,6 +62,7 @@ sub usage { } if ($status != 1) { + print(" -c Put checksum in load information block.\n"); print(" -h Print out this message and exit.\n"); print(" -l Linux mode; if present, copy 'image' and 'initrd' sections.\n"); print(" -v Verbose. Print out lots of ELF information.\n"); @@ -148,10 +150,14 @@ sub file_check { sub decode_options { - if (!getopts("hlvV")) { + if (!getopts("chlvV")) { usage(1); } + if ($opt_c) { + $do_checksum = 1; + } + if ($opt_h) { usage(0); } @@ -360,14 +366,20 @@ require '../utils/elf.pl'; $output_size += $initrd_size; } - $num_blocks = $output_size / 512 + 1; + # + # Compute size with header + # + + $header = pack("H8N7", "0052504f", 0, 0, 0, 0, 0, 0, 0); + $num_blocks = ($output_size + length($header) + 511) / 512; # # Write IBM PowerPC evaluation board boot_block_t header # $header = pack("H8N7", "0052504f", $text_addr, $num_blocks, 0, - $text_addr, 0, 0, 0); + $text_addr, 0, 0, 0); + $bytes = length($header); @@ -412,18 +424,57 @@ require '../utils/elf.pl'; # # Pad to a multiple of 512 bytes + # If the (size of the boot image mod 512) is between 509 and 511 bytes + # then the tftp to the Walnut fails. This may be fixed in more recent + # Walnut bootrom. # - $pad_size = 512 - (length($header) + $output_size) % 512; + $pad_size = 512 - ((length($header) + $output_size) % 512); + if ($pad_size == 512) { + $pad_size = 0; + } + + if ($pad_size != 0) { + + if ($verbose) { + print("Padding boot image by an additional $pad_size bytes.\n"); + } + + $pad_string = pack("H8","deadbeef") x 128; + + syswrite(BOOT, $pad_string, $pad_size) or + die "Could not pad boot image in output file.\n"; - if ($verbose) { - print("Padding boot image by an additional $pad_size bytes.\n"); } - $pad_string = pack(("H8","deadbeef") x 128); + # + # Compute 32 bit checksum over entire file. + # + + if ($do_checksum) { - syswrite(BOOT, $pad_string, $pad_size) or - die "Could not pad boot image in output file.\n"; + close(BOOT); + open(BOOT, "+<$ofile") || die "Cannot open output file"; + undef $/; + $temp = unpack("%32N*", <BOOT>); + # Solaris and PPC Linux return 0x80000000 for "-$temp" when $temp + # is negative. "~($temp - 1)" negates $temp properly. + $csum = ~($temp - 1); + printf("Checksum = 0x%08x\r\n", $csum); + + # + # Rewrite IBM PowerPC evaluation board boot_block_t header, + # this time with the checksum included + # + + $header = pack("H8N7", "0052504f", $text_addr, $num_blocks, 0, + $text_addr, $csum, 0, 0); + + seek(BOOT, 0, 0); + syswrite(BOOT, $header, length($header)) or + die("Could not write boot image header to output file."); + + } # # Clean-up and leave diff --git a/arch/ppc/config.in b/arch/ppc/config.in index cd1c9fd84249..092b6bd384cc 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.config.in 1.24 05/21/01 00:48:24 cort +# BK Id: SCCS/s.config.in 1.30 06/27/01 14:49:58 trini # # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. @@ -84,9 +84,9 @@ fi if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ]; then choice 'Machine Type' \ - "PowerMac/PReP/MTX/CHRP CONFIG_ALL_PPC \ - Gemini CONFIG_GEMINI \ - APUS CONFIG_APUS" PowerMac/PReP/MTX/CHRP + "CHRP/PowerMac/PReP CONFIG_ALL_PPC \ + Amgia-APUS CONFIG_APUS \ + Synergy-Gemini CONFIG_GEMINI" CHRP/PowerMac/PReP fi if [ "$CONFIG_PPC64BRIDGE" != "y" ]; then diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 4db0d9c025e9..cf5e5b42e132 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.19 05/26/01 14:48:14 paulus +# BK Id: SCCS/s.Makefile 1.22 06/28/01 08:01:06 trini # # # Makefile for the linux kernel. @@ -39,11 +39,7 @@ obj-$(CONFIG_MODULES) += ppc_ksyms.o obj-$(CONFIG_POWER4) += xics.o obj-$(CONFIG_PCI) += pci.o pci-dma.o obj-$(CONFIG_KGDB) += ppc-stub.o -obj-$(CONFIG_PMAC_PBOOK) += sleep.o obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_PPC_RTAS) += error_log.o proc_rtas.o -obj-$(CONFIG_NVRAM) += pmac_nvram.o -obj-$(CONFIG_PREP_RESIDUAL) += residual.o obj-$(CONFIG_4xx) += ppc4xx_pic.o obj-$(CONFIG_OAK) += oak_setup.o obj-$(CONFIG_WALNUT) += walnut_setup.o @@ -52,12 +48,10 @@ obj-$(CONFIG_PCI) += galaxy_pci.o endif obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o ifeq ($(CONFIG_8xx),y) -obj-$(CONFIG_PCI) += qspan_pci.c +obj-$(CONFIG_PCI) += qspan_pci.o ifndef CONFIG_MATH_EMULATION obj-y += softemu8xx.o endif -else -obj-y += hashtable.o endif obj-$(CONFIG_MBX) += i8259.o obj-$(CONFIG_APUS) += apus_setup.o @@ -69,7 +63,11 @@ obj-$(CONFIG_ALL_PPC) += pmac_pic.o pmac_setup.o pmac_time.o prom.o \ chrp_time.o chrp_pci.o open_pic.o \ indirect_pci.o i8259.o prep_pci.o \ prep_time.o prep_nvram.o prep_setup.o +obj-$(CONFIG_NVRAM) += pmac_nvram.o obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o +obj-$(CONFIG_PMAC_PBOOK) += sleep.o +obj-$(CONFIG_PPC_RTAS) += error_log.o proc_rtas.o +obj-$(CONFIG_PREP_RESIDUAL) += residual.o obj-$(CONFIG_GEMINI) += gemini_prom.o gemini_pci.o gemini_setup.o \ open_pic.o obj-$(CONFIG_8260) += m8260_setup.o ppc8260_pic.o diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c index b968a0502d64..6bfddcf39ac9 100644 --- a/arch/ppc/kernel/chrp_pci.c +++ b/arch/ppc/kernel/chrp_pci.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.chrp_pci.c 1.16 05/17/01 18:14:21 cort + * BK Id: SCCS/s.chrp_pci.c 1.17 06/28/01 16:11:56 paulus */ /* * CHRP pci routines. @@ -27,11 +27,6 @@ #include "open_pic.h" #include "pci.h" - -#ifdef CONFIG_POWER4 -extern unsigned long pci_address_offset(int, unsigned int); -#endif /* CONFIG_POWER4 */ - /* LongTrail */ #define pci_config_addr(dev, offset) \ (GG2_PCI_CONFIG_BASE | ((dev->bus->number)<<16) | ((dev->devfn)<<8) | (offset)) @@ -212,34 +207,6 @@ hydra_init(void) return 1; } -#ifdef CONFIG_POWER4 -static void -power4_fixup_dev(struct pci_dev *dev) -{ - int i; - unsigned long offset; - - for (i = 0; i < 6; ++i) { - if (dev->resource[i].start == 0) - continue; - offset = pci_address_offset(dev->bus->number, - dev->resource[i].flags); - if (offset) { - dev->resource[i].start += offset; - dev->resource[i].end += offset; - printk("device %x.%x[%d] now [%lx..%lx]\n", - dev->bus->number, dev->devfn, i, - dev->resource[i].start, - dev->resource[i].end); - } - /* zap the 2nd function of the winbond chip */ - if (dev->resource[i].flags & IORESOURCE_IO - && dev->bus->number == 0 && dev->devfn == 0x81) - dev->resource[i].flags &= ~IORESOURCE_IO; - } -} -#endif /* CONFIG_POWER4 */ - void __init chrp_pcibios_fixup(void) { @@ -261,48 +228,9 @@ chrp_pcibios_fixup(void) pci_write_config_word(dev, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); } -#ifdef CONFIG_POWER4 - power4_fixup_dev(dev); -#endif } } -#if 0 -static struct { - /* parent is iomem */ - struct resource ram, pci_mem, isa_mem, pci_io, pci_cfg, rom_exp, flash; - /* parent is isa_mem */ - struct resource nvram; -} gg2_resources = { - ram: { "RAM", 0x00000000, 0xbfffffff, IORESOURCE_MEM }, - pci_mem: { "GG2 PCI mem", 0xc0000000, 0xf6ffffff, IORESOURCE_MEM }, - isa_mem: { "GG2 ISA mem", 0xf7000000, 0xf7ffffff }, - pci_io: { "GG2 PCI I/O", 0xf8000000, 0xf8ffffff }, - pci_cfg: { "GG2 PCI cfg", 0xfec00000, 0xfec7ffff }, - rom_exp: { "ROM exp", 0xff000000, 0xff7fffff, }, - flash: { "Flash ROM", 0xfff80000, 0xffffffff }, - nvram: { "NVRAM", 0xf70e0000, 0xf70e7fff }, -}; - -static void __init gg2_pcibios_fixup(void) -{ - int i; - extern unsigned long *end_of_DRAM; - - chrp_pcibios_fixup(); - gg2_resources.ram.end = (unsigned long)end_of_DRAM-PAGE_OFFSET; - for (i = 0; i < 7; i++) - request_resource(&iomem_resource, - &((struct resource *)&gg2_resources)[i]); - request_resource(&gg2_resources.isa_mem, &gg2_resources.nvram); -} - -static void __init gg2_pcibios_fixup_bus(struct pci_bus *bus) -{ - bus->resource[1] = &gg2_resources.pci_mem; -} -#endif /* 0 */ - /* this is largely modeled and stolen after the pmac_pci code -- tgall */ @@ -314,14 +242,16 @@ ibm_add_bridges(struct device_node *dev) struct pci_controller *hose; volatile unsigned char *cfg; unsigned int *dma; -#ifdef CONFIG_POWER3 struct device_node *root = find_path_device("/"); +#ifdef CONFIG_POWER3 unsigned int *opprop = (unsigned int *) get_property(root, "platform-open-pic", NULL); int i; #endif for(; dev != NULL; dev = dev->next, ++index) { + if (dev->parent != root) + continue; if (dev->n_addrs < 1) { printk(KERN_WARNING "Can't use %s: no address\n", dev->full_name); @@ -374,23 +304,6 @@ ibm_add_bridges(struct device_node *dev) } } -#ifdef CONFIG_POWER4 -void __init -power4_add_bridge(void) -{ - struct pci_controller* hose; - - hose = pcibios_alloc_controller(); - if (!hose) - return; - hose->first_busno = 0; - hose->last_busno = 0xff; - - hose->ops = &rtas_pci_ops; - pci_dram_offset = 0; -} -#endif /* CONFIG_POWER4 */ - void __init chrp_find_bridges(void) { @@ -400,9 +313,6 @@ chrp_find_bridges(void) ppc_md.pcibios_fixup = chrp_pcibios_fixup; -#ifdef CONFIG_POWER4 - power4_add_bridge(); -#else /* CONFIG_POWER4 */ model = get_property(find_path_device("/"), "model", NULL); if (!strncmp("MOT", model, 3)) { struct pci_controller *hose; @@ -452,36 +362,4 @@ chrp_find_bridges(void) hose->ops = &gg2_pci_ops; pci_dram_offset = 0; pci_process_bridge_OF_ranges(hose, find_devices("pci"), 1); -// ppc_md.pcibios_fixup = gg2_pcibios_fixup; -// ppc_md.pcibios_fixup_bus = gg2_pcibios_fixup_bus; -#endif /* CONFIG_POWER4 */ } - -#ifdef CONFIG_PPC64BRIDGE -#ifdef CONFIG_POWER4 -/* - * Hack alert!!! - * 64-bit machines like POWER3 and POWER4 have > 32 bit - * physical addresses. For now we remap particular parts - * of the 32-bit physical address space that the Linux - * page table gives us into parts of the physical address - * space above 4GB so we can access the I/O devices. - */ -unsigned long pci_address_offset(int busnr, unsigned int flags) -{ - unsigned long offset = 0; - - if (busnr >= 0x1e) { - if (flags & IORESOURCE_IO) - offset = -0x100000; - else if (flags & IORESOURCE_MEM) - offset = 0x38000000; - } else if (busnr <= 0xf) { - if (flags & IORESOURCE_MEM) - offset = -0x40000000; - else - } - return offset; -} -#endif /* CONFIG_POWER4 */ -#endif /* CONFIG_PPC64BRIDGE */ diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index 7f7134a84543..8e10984d593a 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.entry.S 1.15 06/09/01 22:16:38 paulus + * BK Id: SCCS/s.entry.S 1.17 06/19/01 22:40:51 paulus */ /* * PowerPC version @@ -283,6 +283,7 @@ _GLOBAL(_switch) */ mfmsr r0 /* Get current interrupt state */ rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ + SYNC /* Some chip revs have problems here... */ mtmsr r0 /* Update machine state */ lwz r0,_MSR(r1) diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c index 7a43307764a7..3720c49b4052 100644 --- a/arch/ppc/kernel/feature.c +++ b/arch/ppc/kernel/feature.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.feature.c 1.10 05/17/01 18:14:21 cort + * BK Id: SCCS/s.feature.c 1.14 06/17/01 09:33:37 trini */ /* * arch/ppc/kernel/feature.c @@ -288,11 +288,11 @@ static struct board_features_t { { "AAPL,PowerBook1998", FTR_CAN_SLEEP }, /* Wallstreet PowerBook */ { "PowerBook1,1", FTR_CAN_SLEEP }, /* 101 (Lombard) PowerBook */ { "PowerBook2,1", FTR_CAN_SLEEP }, /* iBook */ + { "PowerBook4,1", FTR_CAN_NAP|FTR_CAN_SLEEP }, /* iBook Dual USB */ { "PowerBook2,2", FTR_CAN_SLEEP /*| FTR_CAN_NAP*/ }, /* iBook FireWire */ { "PowerBook3,1", FTR_CAN_SLEEP|FTR_CAN_NAP| /* PowerBook 2000 (Pismo) */ FTR_HAS_FW_POWER }, { "PowerBook3,2", FTR_CAN_NAP|FTR_CAN_SLEEP }, /* PowerBook Titanium */ - { "PowerBook4,1", FTR_CAN_NAP|FTR_CAN_SLEEP }, /* New polycarbonate iBook */ { NULL, 0 } }; diff --git a/arch/ppc/kernel/hashtable.S b/arch/ppc/kernel/hashtable.S deleted file mode 100644 index e3d6a50cad93..000000000000 --- a/arch/ppc/kernel/hashtable.S +++ /dev/null @@ -1,724 +0,0 @@ -/* - * BK Id: SCCS/s.hashtable.S 1.11 05/17/01 18:14:21 cort - */ -/* - * arch/ppc/kernel/hashtable.S - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP - * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> - * Adapted for Power Macintosh by Paul Mackerras. - * Low-level exception handlers and MMU support - * rewritten by Paul Mackerras. - * Copyright (C) 1996 Paul Mackerras. - * - * This file contains low-level assembler routines for managing - * the PowerPC MMU hash table. (PPC 8xx processors don't use a - * hash table, so this file is not used on them.) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include "ppc_asm.h" -#include <asm/processor.h> -#include <asm/page.h> -#include <linux/config.h> - -/* - * Load a PTE into the hash table, if possible. - * The address is in r3, and r4 contains access flags: - * _PAGE_USER (4) if a user-mode access, ored with - * _PAGE_RW (2) if a write. r20 contains DSISR or SRR1, - * so bit 1 (0x40000000) is set if the exception was due - * to no matching PTE being found in the hash table. - * SPRG3 contains the physical address of the current task's thread. - * - * Returns to the caller if the access is illegal or there is no - * mapping for the address. Otherwise it places an appropriate PTE - * in the hash table and returns from the exception. - * Uses r0, r2 - r6, ctr, lr. - * - * For speed, 4 of the instructions get patched once the size and - * physical address of the hash table are known. These definitions - * of Hash_base and Hash_bits below are just an example. - */ -Hash_base = 0x180000 -Hash_bits = 12 /* e.g. 256kB hash table */ -Hash_msk = (((1 << Hash_bits) - 1) * 64) - - .globl hash_page -hash_page: -#ifdef CONFIG_PPC64BRIDGE - mfmsr r0 - clrldi r0,r0,1 /* make sure it's in 32-bit mode */ - MTMSRD(r0) - isync -#endif -#ifdef CONFIG_SMP - SAVE_2GPRS(7,r21) - eieio - lis r2,hash_table_lock@h - ori r2,r2,hash_table_lock@l - tophys(r2,r2) - lis r6,0x0fff0000@h - mtctr r6 - mfspr r5,SPRG3 - lwz r0,PROCESSOR-THREAD(r5) - or r0,r0,r6 -10: lwarx r6,0,r2 - cmpi 0,r6,0 - bne- 12f - stwcx. r0,0,r2 - beq+ 11f - /* spin here a bit */ -12: mfctr r7 - li r8,1000 - mtctr r8 -13: - bdnz 13b - mtctr r7 - cmpw r6,r0 - bdnzf 2,10b - tw 31,31,31 -11: eieio - REST_2GPRS(7, r21) -#endif - /* Get PTE (linux-style) and check access */ - lis r0,KERNELBASE@h /* check if kernel address */ - cmplw 0,r3,r0 - mfspr r2,SPRG3 /* current task's THREAD (phys) */ - lwz r5,PGDIR(r2) /* virt page-table root */ - blt+ 112f /* assume user more likely */ - lis r5,swapper_pg_dir@ha /* if kernel address, use */ - addi r5,r5,swapper_pg_dir@l /* kernel page table */ -112: tophys(r5,r5) /* convert to phys addr */ - rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */ - lwz r5,0(r5) /* get pmd entry */ - rlwinm. r5,r5,0,0,19 /* extract address of pte page */ -#ifdef CONFIG_SMP - beq- hash_page_out /* return if no mapping */ -#else - /* XXX it seems like the 601 will give a machine fault on the - rfi if its alignment is wrong (bottom 4 bits of address are - 8 or 0xc) and we have had a not-taken conditional branch - to the address following the rfi. */ - beqlr- -#endif - tophys(r2,r5) - rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ - ori r4,r4,1 /* set _PAGE_PRESENT bit in access */ - rlwinm r5,r4,5,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */ - rlwimi r5,r4,7,22,22 /* _PAGE_RW -> _PAGE_HWWRITE */ - ori r5,r5,0x100 /* set _PAGE_ACCESSED */ -retry: - lwz r6,0(r2) /* get linux-style pte */ - andc. r0,r4,r6 /* check access & ~permission */ -#ifdef CONFIG_SMP - bne- hash_page_out /* return if access not permitted */ -#else - bnelr- -#endif - andc. r0,r5,r6 /* any bits not yet set? */ - beq 2f - - /* Update the linux PTE atomically */ - lwarx r0,0,r2 /* refetch the pte and check */ - cmpw 0,r0,r6 /* that it hasn't been changed */ - bne- retry /* retry if it has */ - or r6,r6,r5 /* set accessed/dirty bits */ - stwcx. r6,0,r2 /* attempt to update PTE */ - bne- retry /* retry if someone got there first */ - - /* Convert linux-style PTE to low word of PPC-style PTE */ -2: rlwinm r4,r6,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ - rlwimi r6,r6,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ - ori r4,r4,0xe04 /* clear out reserved bits */ - andc r6,r6,r4 /* PP=2 or 0, when _PAGE_HWWRITE */ - -#ifdef CONFIG_POWER4 - /* - * XXX hack hack hack - translate 32-bit "physical" addresses - * in the linux page tables to 42-bit real addresses in such - * a fashion that we can get at the I/O we need to access. - * -- paulus - */ - cmpwi 0,r6,0 - rlwinm r4,r6,16,16,30 - bge 57f - cmplwi 0,r4,0xfe00 - li r5,0x3fd - bne 56f - li r5,0x3ff -56: sldi r5,r5,32 - or r6,r6,r5 -57: -#endif - -#ifdef CONFIG_PPC64BRIDGE - /* Construct the high word of the PPC-style PTE */ - mfsrin r5,r3 /* get segment reg for segment */ - rlwinm r5,r5,0,5,31 - sldi r5,r5,12 - ori r5,r5,1 /* set V (valid) bit */ - rlwimi r5,r3,16,20,24 /* put in API (abbrev page index) */ - /* Get the address of the primary PTE group in the hash table */ - .globl hash_page_patch_A -hash_page_patch_A: - lis r4,Hash_base@h /* base address of hash table */ - rlwimi r4,r5,32-5,25-Hash_bits,24 /* (VSID & hash_mask) << 7 */ - rlwinm r0,r3,32-5,25-Hash_bits,24 /* (PI & hash_mask) << 7 */ - xor r4,r4,r0 /* make primary hash */ - li r2,8 /* PTEs/group */ - -#ifndef CONFIG_SMP - /* We don't do this for SMP - another cpu could have put in - the appropriate PTE since we took the exception. -- paulus. */ - /* See whether it was a PTE not found exception or a - protection violation. */ - andis. r0,r20,0x4000 - bne 10f /* no PTE: go look for an empty slot */ -#endif /* CONFIG_SMP */ - tlbie r3 /* invalidate TLB entry */ - - /* Search the primary PTEG for a PTE whose 1st dword matches r5 */ - mtctr r2 - addi r3,r4,-16 -1: ldu r0,16(r3) /* get next PTE */ - cmpd 0,r0,r5 - bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ - beq+ found_slot - - /* Search the secondary PTEG for a matching PTE */ - ori r5,r5,0x2 /* set H (secondary hash) bit */ - .globl hash_page_patch_B -hash_page_patch_B: - xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ - xori r3,r3,0xff80 - addi r3,r3,-16 - mtctr r2 -2: ldu r0,16(r3) - cmpd 0,r0,r5 - bdnzf 2,2b - beq+ found_slot - xori r5,r5,0x2 /* clear H bit again */ - - /* Search the primary PTEG for an empty slot */ -10: mtctr r2 - addi r3,r4,-16 /* search primary PTEG */ -1: ldu r0,16(r3) /* get next PTE */ - andi. r0,r0,1 - bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ - beq+ found_empty - - /* Search the secondary PTEG for an empty slot */ - ori r5,r5,0x2 /* set H (secondary hash) bit */ - .globl hash_page_patch_C -hash_page_patch_C: - xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ - xori r3,r3,0xff80 - addi r3,r3,-16 - mtctr r2 -2: ldu r0,16(r3) - andi. r0,r0,1 - bdnzf 2,2b - beq+ found_empty - - /* - * Choose an arbitrary slot in the primary PTEG to overwrite. - * Since both the primary and secondary PTEGs are full, and we - * have no information that the PTEs in the primary PTEG are - * more important or useful than those in the secondary PTEG, - * and we know there is a definite (although small) speed - * advantage to putting the PTE in the primary PTEG, we always - * put the PTE in the primary PTEG. - */ - xori r5,r5,0x2 /* clear H bit again */ - lis r3,next_slot@ha - tophys(r3,r3) - lwz r2,next_slot@l(r3) - addi r2,r2,16 - andi. r2,r2,0x70 -#ifdef CONFIG_POWER4 - /* - * Since we don't have BATs on POWER4, we rely on always having - * PTEs in the hash table to map the hash table and the code - * that manipulates it in virtual mode, namely flush_hash_page and - * flush_hash_segments. Otherwise we can get a DSI inside those - * routines which leads to a deadlock on the hash_table_lock on - * SMP machines. We avoid this by never overwriting the first - * PTE of each PTEG if it is already valid. - * -- paulus. - */ - bne 102f - li r2,0x10 -102: -#endif /* CONFIG_POWER4 */ - stw r2,next_slot@l(r3) - add r3,r4,r2 -11: - /* update counter of evicted pages */ - lis r2,htab_evicts@ha - tophys(r2,r2) - lwz r4,htab_evicts@l(r2) - addi r4,r4,1 - stw r4,htab_evicts@l(r2) - -#ifndef CONFIG_SMP - /* Store PTE in PTEG */ -found_empty: - std r5,0(r3) -found_slot: - std r6,8(r3) - -#else /* CONFIG_SMP */ -/* - * Between the tlbie above and updating the hash table entry below, - * another CPU could read the hash table entry and put it in its TLB. - * There are 3 cases: - * 1. using an empty slot - * 2. updating an earlier entry to change permissions (i.e. enable write) - * 3. taking over the PTE for an unrelated address - * - * In each case it doesn't really matter if the other CPUs have the old - * PTE in their TLB. So we don't need to bother with another tlbie here, - * which is convenient as we've overwritten the register that had the - * address. :-) The tlbie above is mainly to make sure that this CPU comes - * and gets the new PTE from the hash table. - * - * We do however have to make sure that the PTE is never in an invalid - * state with the V bit set. - */ -found_empty: -found_slot: - li r0,1 - andc r5,r5,r0 /* clear V (valid) bit in PTE */ - std r5,0(r3) - sync - tlbsync - sync - std r6,8(r3) /* put in correct RPN, WIMG, PP bits */ - sync - ori r5,r5,1 - std r5,0(r3) /* finally set V bit in PTE */ -#endif /* CONFIG_SMP */ - -#else /* CONFIG_PPC64BRIDGE */ - - /* Construct the high word of the PPC-style PTE */ - mfsrin r5,r3 /* get segment reg for segment */ - rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */ - oris r5,r5,0x8000 /* set V (valid) bit */ - rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */ - /* Get the address of the primary PTE group in the hash table */ - .globl hash_page_patch_A -hash_page_patch_A: - lis r4,Hash_base@h /* base address of hash table */ - rlwimi r4,r5,32-1,26-Hash_bits,25 /* (VSID & hash_mask) << 6 */ - rlwinm r0,r3,32-6,26-Hash_bits,25 /* (PI & hash_mask) << 6 */ - xor r4,r4,r0 /* make primary hash */ - li r2,8 /* PTEs/group */ - -#ifndef CONFIG_SMP - /* We don't do this for SMP - another cpu could have put in - the appropriate PTE since we took the exception. -- paulus. */ - /* See whether it was a PTE not found exception or a - protection violation. */ - andis. r0,r20,0x4000 - bne 10f /* no PTE: go look for an empty slot */ -#endif /* CONFIG_SMP */ - tlbie r3 /* invalidate TLB entry */ - - /* Search the primary PTEG for a PTE whose 1st word matches r5 */ - mtctr r2 - addi r3,r4,-8 -1: lwzu r0,8(r3) /* get next PTE */ - cmp 0,r0,r5 - bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ - beq+ found_slot - - /* Search the secondary PTEG for a matching PTE */ - ori r5,r5,0x40 /* set H (secondary hash) bit */ - .globl hash_page_patch_B -hash_page_patch_B: - xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ - xori r3,r3,0xffc0 - addi r3,r3,-8 - mtctr r2 -2: lwzu r0,8(r3) - cmp 0,r0,r5 - bdnzf 2,2b - beq+ found_slot - xori r5,r5,0x40 /* clear H bit again */ - - /* Search the primary PTEG for an empty slot */ -10: mtctr r2 - addi r3,r4,-8 /* search primary PTEG */ -1: lwzu r0,8(r3) /* get next PTE */ - rlwinm. r0,r0,0,0,0 /* only want to check valid bit */ - bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ - beq+ found_empty - - /* Search the secondary PTEG for an empty slot */ - ori r5,r5,0x40 /* set H (secondary hash) bit */ - .globl hash_page_patch_C -hash_page_patch_C: - xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ - xori r3,r3,0xffc0 - addi r3,r3,-8 - mtctr r2 -2: - lwzu r0,8(r3) - rlwinm. r0,r0,0,0,0 /* only want to check valid bit */ - bdnzf 2,2b - beq+ found_empty - - /* - * Choose an arbitrary slot in the primary PTEG to overwrite. - * Since both the primary and secondary PTEGs are full, and we - * have no information that the PTEs in the primary PTEG are - * more important or useful than those in the secondary PTEG, - * and we know there is a definite (although small) speed - * advantage to putting the PTE in the primary PTEG, we always - * put the PTE in the primary PTEG. - */ - xori r5,r5,0x40 /* clear H bit again */ - lis r3,next_slot@ha - tophys(r3,r3) - lwz r2,next_slot@l(r3) - addi r2,r2,8 - andi. r2,r2,0x38 - stw r2,next_slot@l(r3) - add r3,r4,r2 -11: - /* update counter of evicted pages */ - lis r2,htab_evicts@ha - tophys(r2,r2) - lwz r4,htab_evicts@l(r2) - addi r4,r4,1 - stw r4,htab_evicts@l(r2) - -#ifndef CONFIG_SMP - /* Store PTE in PTEG */ -found_empty: - stw r5,0(r3) -found_slot: - stw r6,4(r3) - -#else /* CONFIG_SMP */ -/* - * Between the tlbie above and updating the hash table entry below, - * another CPU could read the hash table entry and put it in its TLB. - * There are 3 cases: - * 1. using an empty slot - * 2. updating an earlier entry to change permissions (i.e. enable write) - * 3. taking over the PTE for an unrelated address - * - * In each case it doesn't really matter if the other CPUs have the old - * PTE in their TLB. So we don't need to bother with another tlbie here, - * which is convenient as we've overwritten the register that had the - * address. :-) The tlbie above is mainly to make sure that this CPU comes - * and gets the new PTE from the hash table. - * - * We do however have to make sure that the PTE is never in an invalid - * state with the V bit set. - */ -found_empty: -found_slot: - rlwinm r5,r5,0,1,31 /* clear V (valid) bit in PTE */ - stw r5,0(r3) - sync - tlbsync - sync - stw r6,4(r3) /* put in correct RPN, WIMG, PP bits */ - sync - oris r5,r5,0x8000 - stw r5,0(r3) /* finally set V bit in PTE */ -#endif /* CONFIG_SMP */ -#endif /* CONFIG_PPC64BRIDGE */ - - sync /* make sure pte updates get to memory */ - -/* - * Update the hash table miss count. We only want misses here - * that _are_ valid addresses and have a pte otherwise we don't - * count it as a reload. do_page_fault() takes care of bad addrs - * and entries that need linux-style pte's created. - * - * safe to use r2 here since we're not using it as current yet - * update the htab misses count - * -- Cort - */ - lis r2,htab_reloads@ha - tophys(r2,r2) - lwz r3,htab_reloads@l(r2) - addi r3,r3,1 - stw r3,htab_reloads@l(r2) - -#ifdef CONFIG_SMP - lis r2,hash_table_lock@ha - tophys(r2,r2) - li r0,0 - stw r0,hash_table_lock@l(r2) - eieio -#endif - - /* Return from the exception */ - lwz r3,_CCR(r21) - lwz r4,_LINK(r21) - lwz r5,_CTR(r21) - mtcrf 0xff,r3 - mtlr r4 - mtctr r5 - lwz r0,GPR0(r21) - lwz r1,GPR1(r21) - lwz r2,GPR2(r21) - lwz r3,GPR3(r21) - lwz r4,GPR4(r21) - lwz r5,GPR5(r21) - lwz r6,GPR6(r21) - /* we haven't used xer */ - mtspr SRR1,r23 - mtspr SRR0,r22 - lwz r20,GPR20(r21) - lwz r22,GPR22(r21) - lwz r23,GPR23(r21) - lwz r21,GPR21(r21) - RFI - -#ifdef CONFIG_SMP -hash_page_out: - lis r2,hash_table_lock@ha - tophys(r2,r2) - li r0,0 - stw r0,hash_table_lock@l(r2) - eieio - blr - - .data - .globl hash_table_lock -hash_table_lock: - .long 0 -#endif /* CONFIG_SMP */ - - .data -next_slot: - .long 0 - - .text -/* - * Flush entries from the hash table with VSIDs in the range - * given. - */ -_GLOBAL(flush_hash_segments) - lis r5,Hash@ha - lwz r5,Hash@l(r5) /* base of hash table */ - cmpwi 0,r5,0 - bne+ 99f - tlbia - sync -#ifdef CONFIG_SMP - tlbsync - sync -#endif - blr -99: -#if defined(CONFIG_SMP) || defined(CONFIG_PPC64BRIDGE) - /* Note - we had better not do anything which could generate - a hash table miss while we have the hash table locked, - or we'll get a deadlock. -paulus */ - mfmsr r10 - SYNC - rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ - mtmsr r0 - SYNC -#endif -#ifdef CONFIG_SMP - lis r9,hash_table_lock@h - ori r9,r9,hash_table_lock@l - lwz r8,PROCESSOR(r2) - oris r8,r8,8 -10: lwarx r6,0,r9 - cmpi 0,r6,0 - bne- 10b - stwcx. r8,0,r9 - bne- 10b - eieio -#endif -#ifndef CONFIG_PPC64BRIDGE - rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */ - oris r3,r3,0x8000 /* set V bit */ - rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */ - oris r4,r4,0x8000 - ori r4,r4,0x7f - lis r6,Hash_size@ha - lwz r6,Hash_size@l(r6) /* size in bytes */ - srwi r6,r6,3 /* # PTEs */ - mtctr r6 - addi r5,r5,-8 - li r0,0 -1: lwzu r6,8(r5) /* get next tag word */ - cmplw 0,r6,r3 - cmplw 1,r6,r4 - cror 0,0,5 /* set cr0.lt if out of range */ - blt 2f /* branch if out of range */ - stw r0,0(r5) /* invalidate entry */ -2: bdnz 1b /* continue with loop */ -#else /* CONFIG_PPC64BRIDGE */ - rldic r3,r3,12,20 /* put VSID lower limit in position */ - ori r3,r3,1 /* set V bit */ - rldic r4,r4,12,20 /* put VSID upper limit in position */ - ori r4,r4,0xfff /* set V bit, API etc. */ - lis r6,Hash_size@ha - lwz r6,Hash_size@l(r6) /* size in bytes */ - srwi r6,r6,4 /* # PTEs */ - mtctr r6 - addi r5,r5,-16 - li r0,0 -1: ldu r6,16(r5) /* get next tag word */ - cmpld 0,r6,r3 - cmpld 1,r6,r4 - cror 0,0,5 /* set cr0.lt if out of range */ - blt 2f /* branch if out of range */ - std r0,0(r5) /* invalidate entry */ -2: bdnz 1b /* continue with loop */ -#endif /* CONFIG_PPC64BRIDGE */ - - sync - tlbia - sync -#ifdef CONFIG_SMP - tlbsync - sync - lis r3,hash_table_lock@ha - stw r0,hash_table_lock@l(r3) -#endif -#if defined(CONFIG_SMP) || defined(CONFIG_PPC64BRIDGE) - mtmsr r10 - SYNC -#endif - blr - -/* - * Flush the entry for a particular page from the hash table. - * - * flush_hash_page(unsigned context, unsigned long va) - */ -_GLOBAL(flush_hash_page) - lis r6,Hash@ha - lwz r6,Hash@l(r6) /* hash table base */ - cmpwi 0,r6,0 /* hash table in use? */ - bne+ 99f - tlbie r4 /* in hw tlb too */ - sync -#ifdef CONFIG_SMP - tlbsync - sync -#endif - blr -99: -#if defined(CONFIG_SMP) || defined(CONFIG_PPC64BRIDGE) - /* Note - we had better not do anything which could generate - a hash table miss while we have the hash table locked, - or we'll get a deadlock. -paulus */ - mfmsr r10 - SYNC - rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ - mtmsr r0 - SYNC -#endif -#ifdef CONFIG_SMP - lis r9,hash_table_lock@h - ori r9,r9,hash_table_lock@l - lwz r8,PROCESSOR(r2) - oris r8,r8,9 -10: lwarx r7,0,r9 - cmpi 0,r7,0 - bne- 11f - stwcx. r8,0,r9 - beq+ 12f -11: lwz r7,0(r9) - cmpi 0,r7,0 - beq 10b - b 11b -12: eieio -#endif -#ifndef CONFIG_PPC64BRIDGE - rlwinm r3,r3,11,1,20 /* put context into vsid */ - rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */ - oris r3,r3,0x8000 /* set V (valid) bit */ - rlwimi r3,r4,10,26,31 /* put in API (abbrev page index) */ - rlwinm r7,r4,32-6,10,25 /* get page index << 6 */ - rlwinm r5,r3,32-1,7,25 /* vsid << 6 */ - xor r7,r7,r5 /* primary hash << 6 */ - lis r5,Hash_mask@ha - lwz r5,Hash_mask@l(r5) /* hash mask */ - slwi r5,r5,6 /* << 6 */ - and r7,r7,r5 - add r6,r6,r7 /* address of primary PTEG */ - li r8,8 - mtctr r8 - addi r7,r6,-8 -1: lwzu r0,8(r7) /* get next PTE */ - cmpw 0,r0,r3 /* see if tag matches */ - bdnzf 2,1b /* while --ctr != 0 && !cr0.eq */ - beq 3f /* if we found it */ - ori r3,r3,0x40 /* set H (alt. hash) bit */ - xor r6,r6,r5 /* address of secondary PTEG */ - mtctr r8 - addi r7,r6,-8 -2: lwzu r0,8(r7) /* get next PTE */ - cmpw 0,r0,r3 /* see if tag matches */ - bdnzf 2,2b /* while --ctr != 0 && !cr0.eq */ - bne 4f /* if we didn't find it */ -3: li r0,0 - stw r0,0(r7) /* invalidate entry */ -#else /* CONFIG_PPC64BRIDGE */ - rldic r3,r3,16,16 /* put context into vsid (<< 12) */ - rlwimi r3,r4,16,16,24 /* top 4 bits of va and API */ - ori r3,r3,1 /* set V (valid) bit */ - rlwinm r7,r4,32-5,9,24 /* get page index << 7 */ - srdi r5,r3,5 /* vsid << 7 */ - rlwinm r5,r5,0,1,24 /* vsid << 7 (limited to 24 bits) */ - xor r7,r7,r5 /* primary hash << 7 */ - lis r5,Hash_mask@ha - lwz r5,Hash_mask@l(r5) /* hash mask */ - slwi r5,r5,7 /* << 7 */ - and r7,r7,r5 - add r6,r6,r7 /* address of primary PTEG */ - li r8,8 - mtctr r8 - addi r7,r6,-16 -1: ldu r0,16(r7) /* get next PTE */ - cmpd 0,r0,r3 /* see if tag matches */ - bdnzf 2,1b /* while --ctr != 0 && !cr0.eq */ - beq 3f /* if we found it */ - ori r3,r3,2 /* set H (alt. hash) bit */ - xor r6,r6,r5 /* address of secondary PTEG */ - mtctr r8 - addi r7,r6,-16 -2: ldu r0,16(r7) /* get next PTE */ - cmpd 0,r0,r3 /* see if tag matches */ - bdnzf 2,2b /* while --ctr != 0 && !cr0.eq */ - bne 4f /* if we didn't find it */ -3: li r0,0 - std r0,0(r7) /* invalidate entry */ -#endif /* CONFIG_PPC64BRIDGE */ -4: sync - tlbie r4 /* in hw tlb too */ - sync -#ifdef CONFIG_SMP - tlbsync - sync - li r0,0 - stw r0,0(r9) /* clear hash_table_lock */ -#endif -#if defined(CONFIG_SMP) || defined(CONFIG_PPC64BRIDGE) - mtmsr r10 - SYNC -#endif - blr diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 0e9eb82f09d9..0b8caba23e49 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.head.S 1.21 05/23/01 00:38:42 cort + * BK Id: SCCS/s.head.S 1.23 06/28/01 15:50:16 paulus */ /* * PowerPC version @@ -25,11 +25,12 @@ * */ +#include <linux/config.h> #include "ppc_asm.h" #include <asm/processor.h> #include <asm/page.h> -#include <linux/config.h> #include <asm/mmu.h> +#include <asm/pgtable.h> #ifdef CONFIG_APUS #include <asm/amigappc.h> @@ -177,7 +178,7 @@ __after_mmu_off: mtspr SDR1,r4 slbia lis r5,0x2000 /* set pseudo-segment reg 12 */ - ori r5,r5,12 + ori r5,r5,0x0ccc mtsr 12,r5 #endif /* CONFIG_POWER4 */ @@ -312,9 +313,8 @@ DataAccess: mfspr r20,DSISR andis. r0,r20,0xa470 /* weird error? */ bne 1f /* if not, try to put a PTE */ - mfspr r3,DAR /* into the hash table */ - rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */ - rlwimi r4,r20,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */ + mfspr r4,DAR /* into the hash table */ + rlwinm r3,r20,32-15,21,21 /* DSISR_STORE -> _PAGE_RW */ bl hash_page 1: stw r20,_DSISR(r21) mr r5,r20 @@ -354,9 +354,8 @@ InstructionAccess: #endif /* CONFIG_PPC64BRIDGE */ andis. r0,r23,0x4000 /* no pte found? */ beq 1f /* if so, try to put a PTE */ - mr r3,r22 /* into the hash table */ - rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */ - mr r20,r23 /* SRR1 has reason bits */ + li r3,0 /* into the hash table */ + mr r4,r22 /* SRR0 is fault address */ bl hash_page 1: addi r3,r1,STACK_FRAME_OVERHEAD mr r4,r22 @@ -505,10 +504,13 @@ InstructionTLBMiss: lis r1,KERNELBASE@h /* check if kernel address */ cmplw 0,r3,r1 mfspr r2,SPRG3 + li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */ lwz r2,PGDIR(r2) blt+ 112f lis r2,swapper_pg_dir@ha /* if kernel address, use */ addi r2,r2,swapper_pg_dir@l /* kernel page table */ + mfspr r1,SRR1 /* and MSR_PR bit from SRR1 */ + rlwinm r1,r1,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ 112: tophys(r2,r2) rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ lwz r2,0(r2) /* get pmd entry */ @@ -516,21 +518,23 @@ InstructionTLBMiss: beq- InstructionAddressInvalid /* return if no mapping */ tophys(r2,r2) rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ - lwz r1,0(r2) /* get linux-style pte */ - /* setup access flags in r3 */ - mfmsr r3 - rlwinm r3,r3,32-13,30,30 /* MSR_PR -> _PAGE_USER */ - ori r3,r3,1 /* set _PAGE_PRESENT bit in access */ - andc. r3,r3,r1 /* check access & ~permission */ + lwz r3,0(r2) /* get linux-style pte */ + andc. r1,r1,r3 /* check access & ~permission */ bne- InstructionAddressInvalid /* return if access not permitted */ - ori r1,r1,0x100 /* set _PAGE_ACCESSED in pte */ - stw r1,0(r2) /* update PTE (accessed bit) */ + ori r3,r3,_PAGE_ACCESSED /* set _PAGE_ACCESSED in pte */ + /* + * NOTE! We are assuming this is not an SMP system, otherwise + * we would need to update the pte atomically with lwarx/stwcx. + */ + stw r3,0(r2) /* update PTE (accessed bit) */ /* Convert linux-style PTE to low word of PPC-style PTE */ - /* this computation could be done better -- Cort */ - rlwinm r3,r1,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ - rlwimi r1,r1,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ - ori r3,r3,0xe04 /* clear out reserved bits */ - andc r1,r1,r3 /* PP=2 or 0, when _PAGE_HWWRITE */ + rlwinm r1,r3,32-10,31,31 /* _PAGE_RW -> PP lsb */ + rlwinm r2,r3,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */ + and r1,r1,r2 /* writable if _RW and _DIRTY */ + rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */ + rlwimi r3,r3,32-1,31,31 /* _PAGE_USER -> PP lsb */ + ori r1,r1,0xe14 /* clear out reserved bits and M */ + andc r1,r3,r1 /* PP = user? (rw&dirty? 2: 3): 0 */ mtspr RPA,r1 mfspr r3,IMISS tlbli r3 @@ -555,7 +559,6 @@ InstructionAddressInvalid: mfmsr r0 /* Restore "normal" registers */ xoris r0,r0,MSR_TGPR>>16 mtcrf 0x80,r3 /* Restore CR0 */ - SYNC /* Some chip revs have problems here... */ mtmsr r0 b InstructionAccess @@ -576,10 +579,13 @@ DataLoadTLBMiss: lis r1,KERNELBASE@h /* check if kernel address */ cmplw 0,r3,r1 mfspr r2,SPRG3 + li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */ lwz r2,PGDIR(r2) blt+ 112f lis r2,swapper_pg_dir@ha /* if kernel address, use */ addi r2,r2,swapper_pg_dir@l /* kernel page table */ + mfspr r1,SRR1 /* and MSR_PR bit from SRR1 */ + rlwinm r1,r1,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ 112: tophys(r2,r2) rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ lwz r2,0(r2) /* get pmd entry */ @@ -587,22 +593,23 @@ DataLoadTLBMiss: beq- DataAddressInvalid /* return if no mapping */ tophys(r2,r2) rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ - lwz r1,0(r2) /* get linux-style pte */ - /* setup access flags in r3 */ - mfmsr r3 - rlwinm r3,r3,32-13,30,30 /* MSR_PR -> _PAGE_USER */ - ori r3,r3,1 /* set _PAGE_PRESENT bit in access */ - /* save r2 and use it as scratch for the andc. */ - andc. r3,r3,r1 /* check access & ~permission */ + lwz r3,0(r2) /* get linux-style pte */ + andc. r1,r1,r3 /* check access & ~permission */ bne- DataAddressInvalid /* return if access not permitted */ - ori r1,r1,0x100 /* set _PAGE_ACCESSED in pte */ - stw r1,0(r2) /* update PTE (accessed bit) */ + ori r3,r3,_PAGE_ACCESSED /* set _PAGE_ACCESSED in pte */ + /* + * NOTE! We are assuming this is not an SMP system, otherwise + * we would need to update the pte atomically with lwarx/stwcx. + */ + stw r3,0(r2) /* update PTE (accessed bit) */ /* Convert linux-style PTE to low word of PPC-style PTE */ - /* this computation could be done better -- Cort */ - rlwinm r3,r1,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ - rlwimi r1,r1,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ - ori r3,r3,0xe04 /* clear out reserved bits */ - andc r1,r1,r3 /* PP=2 or 0, when _PAGE_HWWRITE */ + rlwinm r1,r3,32-10,31,31 /* _PAGE_RW -> PP lsb */ + rlwinm r2,r3,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */ + and r1,r1,r2 /* writable if _RW and _DIRTY */ + rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */ + rlwimi r3,r3,32-1,31,31 /* _PAGE_USER -> PP lsb */ + ori r1,r1,0xe14 /* clear out reserved bits and M */ + andc r1,r3,r1 /* PP = user? (rw&dirty? 2: 3): 0 */ mtspr RPA,r1 mfspr r3,DMISS tlbld r3 @@ -625,7 +632,6 @@ DataAddressInvalid: mfmsr r0 /* Restore "normal" registers */ xoris r0,r0,MSR_TGPR>>16 mtcrf 0x80,r3 /* Restore CR0 */ - SYNC /* Some chip revs have problems here... */ mtmsr r0 b DataAccess @@ -646,10 +652,13 @@ DataStoreTLBMiss: lis r1,KERNELBASE@h /* check if kernel address */ cmplw 0,r3,r1 mfspr r2,SPRG3 + li r1,_PAGE_RW|_PAGE_USER|_PAGE_PRESENT /* access flags */ lwz r2,PGDIR(r2) blt+ 112f lis r2,swapper_pg_dir@ha /* if kernel address, use */ addi r2,r2,swapper_pg_dir@l /* kernel page table */ + mfspr r1,SRR1 /* and MSR_PR bit from SRR1 */ + rlwinm r1,r1,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ 112: tophys(r2,r2) rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ lwz r2,0(r2) /* get pmd entry */ @@ -657,22 +666,19 @@ DataStoreTLBMiss: beq- DataAddressInvalid /* return if no mapping */ tophys(r2,r2) rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ - lwz r1,0(r2) /* get linux-style pte */ - /* setup access flags in r3 */ - mfmsr r3 - rlwinm r3,r3,32-13,30,30 /* MSR_PR -> _PAGE_USER */ - ori r3,r3,0x5 /* _PAGE_PRESENT|_PAGE_RW */ - /* save r2 and use it as scratch for the andc. */ - andc. r3,r3,r1 /* check access & ~permission */ + lwz r3,0(r2) /* get linux-style pte */ + andc. r1,r1,r3 /* check access & ~permission */ bne- DataAddressInvalid /* return if access not permitted */ - ori r1,r1,0x384 /* set _PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_RW|_PAGE_HWWRITE in pte */ - stw r1,0(r2) /* update PTE (accessed bit) */ + ori r3,r3,_PAGE_ACCESSED|_PAGE_DIRTY + /* + * NOTE! We are assuming this is not an SMP system, otherwise + * we would need to update the pte atomically with lwarx/stwcx. + */ + stw r3,0(r2) /* update PTE (accessed/dirty bits) */ /* Convert linux-style PTE to low word of PPC-style PTE */ - /* this computation could be done better -- Cort */ - rlwinm r3,r1,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ - rlwimi r1,r1,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ - ori r3,r3,0xe04 /* clear out reserved bits */ - andc r1,r1,r3 /* PP=2 or 0, when _PAGE_HWWRITE */ + rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */ + li r1,0xe15 /* clear out reserved bits and M */ + andc r1,r3,r1 /* PP = user? 2: 0 */ mtspr RPA,r1 mfspr r3,DMISS tlbld r3 @@ -901,7 +907,6 @@ load_up_altivec: */ mfmsr r5 oris r5,r5,MSR_VEC@h - SYNC mtmsr r5 /* enable use of AltiVec now */ isync /* @@ -1028,6 +1033,7 @@ giveup_fpu: ori r5,r5,MSR_FP SYNC mtmsr r5 /* enable use of fpu now */ + SYNC isync cmpi 0,r3,0 beqlr- /* if no previous owner, done */ @@ -1384,7 +1390,7 @@ load_up_mmu: lis r3,0x2000 /* Ku = 1, VSID = 0 */ li r4,0 3: mtsrin r3,r4 - addi r3,r3,1 /* increment VSID */ + addi r3,r3,0x111 /* increment VSID */ addis r4,r4,0x1000 /* address of next segment */ bdnz 3b #ifndef CONFIG_POWER4 @@ -1490,7 +1496,8 @@ start_here: * Set up the segment registers for a new context. */ _GLOBAL(set_context) - rlwinm r3,r3,4,8,27 /* VSID = context << 4 */ + mulli r3,r3,897 /* multiply context by skew factor */ + rlwinm r3,r3,4,8,27 /* VSID = (context & 0xfffff) << 4 */ addis r3,r3,0x6000 /* Set Ks, Ku bits */ li r0,12 /* TASK_SIZE / SEGMENT_SIZE */ mtctr r0 @@ -1500,7 +1507,8 @@ _GLOBAL(set_context) slbie r4 #endif /* CONFIG_PPC64BRIDGE */ mtsrin r3,r4 - addi r3,r3,1 /* next VSID */ + addi r3,r3,0x111 /* next VSID */ + rlwinm r3,r3,0,8,3 /* clear out any overflow from VSID field */ addis r4,r4,0x1000 /* address of next segment */ bdnz 3b SYNC diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S index 6f532105b447..c9f4fe9edb65 100644 --- a/arch/ppc/kernel/head_8xx.S +++ b/arch/ppc/kernel/head_8xx.S @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.head_8xx.S 1.11 05/21/01 11:50:00 paulus + * BK Id: SCCS/s.head_8xx.S 1.14 06/28/01 15:50:16 paulus */ /* * arch/ppc/kernel/except_8xx.S @@ -500,6 +500,11 @@ DataStoreTLBMiss: #endif mtspr MD_TWC, r21 + /* Set PP0 to PP1 (== _PAGE_USER) & ~_PAGE_RW */ + rlwimi r20, r20, 32-1, 21, 21 + rlwinm r21, r20, 4, 21, 21 + andc r20, r20, r21 + /* Set four subpage valid bits (24, 25, 26, and 27). * Clear bit 28 (which should be in the PTE, but we do this anyway). */ @@ -602,7 +607,7 @@ DataTLBError: /* Update 'changed', among others. */ - ori r20, r20, _PAGE_DIRTY|_PAGE_HWWRITE|_PAGE_ACCESSED + ori r20, r20, _PAGE_DIRTY|_PAGE_ACCESSED mfspr r21, MD_TWC /* Get pte address again */ stw r20, 0(r21) /* and update pte in table */ @@ -939,6 +944,12 @@ start_here: * ASID compare register with the new "context". */ _GLOBAL(set_context) + /* fetch the pgd from the context_mm array */ + lis r5, context_mm@ha + slwi r6, r3, 2 + add r5, r5, r6 + lwz r5, context_mm@l(r5) /* get the mm */ + lwz r4, MM_PGD(r5) /* get the pgd from the mm */ #ifdef CONFIG_8xx_CPU6 lis r6, cpu6_errata_word@h ori r6, r6, cpu6_errata_word@l diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index 06482e5d5555..c6f1d7ad3ddb 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.irq.c 1.26 06/06/01 22:33:09 paulus + * BK Id: SCCS/s.irq.c 1.28 06/28/01 16:15:56 paulus */ /* * arch/ppc/kernel/irq.c @@ -531,25 +531,21 @@ int do_IRQ(struct pt_regs *regs) { int cpu = smp_processor_id(); int irq; - hardirq_enter( cpu ); + hardirq_enter(cpu); /* every arch is required to have a get_irq -- Cort */ - irq = ppc_md.get_irq( regs ); + irq = ppc_md.get_irq(regs); - if ( irq < 0 ) - { + if (irq >= 0) { + ppc_irq_dispatch_handler( regs, irq ); + } else if (irq != -2) { /* -2 means ignore, already handled */ - if (irq != -2) - { + if (ppc_spurious_interrupts < 10) printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", irq, regs->nip); - /* That's not SMP safe ... but who cares ? */ - ppc_spurious_interrupts++; - } - goto out; + /* That's not SMP safe ... but who cares ? */ + ppc_spurious_interrupts++; } - ppc_irq_dispatch_handler( regs, irq ); -out: hardirq_exit( cpu ); if (softirq_pending(cpu)) diff --git a/arch/ppc/kernel/m8xx_setup.c b/arch/ppc/kernel/m8xx_setup.c index 393990ea0af6..8670c639ccdc 100644 --- a/arch/ppc/kernel/m8xx_setup.c +++ b/arch/ppc/kernel/m8xx_setup.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.m8xx_setup.c 1.17 05/18/01 07:54:04 patch + * BK Id: SCCS/s.m8xx_setup.c 1.20 06/27/01 14:49:58 trini */ /* * linux/arch/ppc/kernel/setup.c @@ -124,12 +124,6 @@ extern char saved_command_line[256]; extern unsigned long find_available_memory(void); extern void m8xx_cpm_reset(uint); -static void ide_interrupt_handler(void* dev_id); - -void __init adbdev_init(void) -{ -} - void __init m8xx_setup_arch(void) { @@ -359,6 +353,12 @@ m8xx_init_IRQ(void) /* * IDE stuff. */ +#ifdef CONFIG_BLK_DEV_MPC8xx_IDE +void ide_interrupt_handler (void *dev) +{ +} +#endif + void m8xx_ide_insw(ide_ioreg_t port, void *buf, int ns) { @@ -512,12 +512,7 @@ void m8xx_ide_init_hwif_ports(hw_regs_t *hw, #endif /* CONFIG_BLK_DEV_MPC8xx_IDE */ } -#endif /* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */ - -/* -------------------------------------------------------------------- */ - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) #ifdef CONFIG_BLK_DEV_MPC8xx_IDE /* PCMCIA Timing */ @@ -577,13 +572,9 @@ m8xx_ide_tuneproc(ide_drive_t *drive, byte pio) if ((reg = pcmp->pcmc_por7 & mask) != 0) pcmp->pcmc_por7 = reg | timing; } - -void ide_interrupt_handler (void *dev) -{ -} - #endif /* CONFIG_BLK_DEV_MPC8xx_IDE */ #endif /* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */ + /* -------------------------------------------------------------------- */ /* diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index f1c70d157333..dd670241774f 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.misc.S 1.16 05/17/01 18:14:21 cort + * BK Id: SCCS/s.misc.S 1.19 06/15/01 13:56:56 paulus */ /* * This file contains miscellaneous low-level functions. @@ -263,10 +263,13 @@ _GLOBAL(_tlbie) * This is a no-op on the 601. */ _GLOBAL(flush_instruction_cache) -#ifdef CONFIG_8xx +#if defined(CONFIG_8xx) isync lis r5, IDC_INVALL@h mtspr IC_CST, r5 +#elif defined(CONFIG_4xx) + lis r3, KERNELBASE@h + iccci 0,r3 #else mfspr r3,PVR rlwinm r3,r3,16,16,31 diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c index 28e1d6fd507e..5fde2f4f57c3 100644 --- a/arch/ppc/kernel/mk_defs.c +++ b/arch/ppc/kernel/mk_defs.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mk_defs.c 1.5 05/17/01 18:14:21 cort + * BK Id: SCCS/s.mk_defs.c 1.8 06/28/01 15:50:16 paulus */ /* * This program is used to generate definitions needed by @@ -117,5 +117,6 @@ main(void) DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result)); DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); DEFINE(CLONE_VM, CLONE_VM); + DEFINE(MM_PGD, offsetof(struct mm_struct, pgd)); return 0; } diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index af78e410dd57..2385686bd057 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pci.c 1.21 05/21/01 01:31:30 cort + * BK Id: SCCS/s.pci.c 1.26 06/28/01 08:02:41 trini */ /* * Common pmac/prep/chrp pci routines. -- Cort @@ -40,11 +40,10 @@ unsigned long isa_io_base = 0; unsigned long isa_mem_base = 0; unsigned long pci_dram_offset = 0; -static u8* pci_to_OF_bus_map; - static void pcibios_fixup_resources(struct pci_dev* dev); #ifdef CONFIG_ALL_PPC static void pcibios_fixup_cardbus(struct pci_dev* dev); +static u8* pci_to_OF_bus_map; #endif /* By default, we don't re-assign bus numbers. We do this only on @@ -73,8 +72,13 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root, u32 new, check; int reg; struct pci_controller* hose = dev->sysdata; + unsigned long io_offset; new = res->start; + if (hose && res->flags & IORESOURCE_IO) { + io_offset = (unsigned long)hose->io_base_virt - isa_io_base; + new -= io_offset; + } if (hose && res->flags & IORESOURCE_MEM) new -= hose->pci_mem_offset; new |= (res->flags & PCI_REGION_FLAG_MASK); @@ -98,40 +102,43 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root, } static void -pcibios_fixup_resources(struct pci_dev* dev) +pcibios_fixup_resources(struct pci_dev *dev) { - struct pci_controller* hose = - (struct pci_controller *)dev->sysdata; + struct pci_controller* hose = (struct pci_controller *)dev->sysdata; int i; + unsigned long offset; + if (!hose) { - printk("No hose for PCI dev %x.%x !\n", dev->bus->number, dev->devfn >> 3); + printk(KERN_ERR "No hose for PCI dev %s!\n", dev->slot_name); return; } for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { struct resource *res = dev->resource + i; - if (!res->start) + if (!res->start || !res->flags) continue; - if ((res->flags & IORESOURCE_MEM) && hose->pci_mem_offset) { - res->start += hose->pci_mem_offset; - res->end += hose->pci_mem_offset; + if (res->end == 0xffffffff) { + DBG("PCI:%s Resource %d [%08lx-%08lx] is unassigned\n", + dev->slot_name, i, res->start, res->end); + res->end -= res->start; + res->start = 0; + continue; + } + offset = 0; + if (res->flags & IORESOURCE_MEM) { + offset = hose->pci_mem_offset; + } else if (res->flags & IORESOURCE_IO) { + offset = (unsigned long) hose->io_base_virt + - isa_io_base; + } + if (offset != 0) { + res->start += offset; + res->end += offset; #ifdef DEBUG - printk("Fixup mem res, dev: %x.%x, res_start: %lx->%lx\n", - dev->bus->number, dev->devfn>>3, res->start-hose->pci_mem_offset, - res->start); + printk("Fixup res %d (%lx) of dev %s: %lx -> %lx\n", + i, res->flags, dev->slot_name, + res->start - offset, res->start); #endif } - - if ((res->flags & IORESOURCE_IO) - && (unsigned long) hose->io_base_virt != isa_io_base) { - unsigned long offs; - - offs = (unsigned long)hose->io_base_virt - isa_io_base; - res->start += offs; - res->end += offs; - printk("Fixup IO res, dev: %x.%x, res_start: %lx->%lx\n", - dev->bus->number, dev->devfn>>3, - res->start - offs, res->start); - } } } @@ -228,22 +235,27 @@ pcibios_allocate_bus_resources(struct list_head *bus_list) { struct list_head *ln; struct pci_bus *bus; - struct pci_dev *dev; - int idx; - struct resource *r, *pr; + int i; + struct resource *res, *pr; /* Depth-First Search on bus tree */ - for (ln=bus_list->next; ln != bus_list; ln=ln->next) { + for (ln = bus_list->next; ln != bus_list; ln=ln->next) { bus = pci_bus_b(ln); - if ((dev = bus->self)) { - for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { - r = &dev->resource[idx]; - if (!r->start) - continue; - pr = pci_find_parent_resource(dev, r); - if (!pr || request_resource(pr, r) < 0) - printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name); - } + for (i = 0; i < 4; ++i) { + if ((res = bus->resource[i]) == NULL || !res->flags) + continue; + if (bus->parent == NULL) + pr = (res->flags & IORESOURCE_IO)? + &ioport_resource: &iomem_resource; + else + pr = pci_find_parent_resource(bus->self, res); + + if (pr && request_resource(pr, res) == 0) + continue; + printk(KERN_ERR "PCI: Cannot allocate resource region " + "%d of PCI bridge %d\n", i, bus->number); + DBG("PCI: resource is %lx..%lx (%lx), parent %p\n", + res->start, res->end, res->flags, pr); } pcibios_allocate_bus_resources(&bus->children); } @@ -253,13 +265,15 @@ static inline void alloc_resource(struct pci_dev *dev, int idx) { struct resource *pr, *r = &dev->resource[idx]; - DBG("PCI:%x:%x:%x: Resource %08lx-%08lx (f=%lx)\n", - dev->bus->number, dev->devfn >> 3, dev->devfn & 7, - r->start, r->end, r->flags); + DBG("PCI:%s: Resource %d: %08lx-%08lx (f=%lx)\n", + dev->slot_name, idx, r->start, r->end, r->flags); pr = pci_find_parent_resource(dev, r); if (!pr || request_resource(pr, r) < 0) { printk(KERN_ERR "PCI: Cannot allocate resource region %d" " of device %s\n", idx, dev->slot_name); + if (pr) + DBG("PCI: parent is %p: %08lx-%08lx (f=%lx)\n", + pr, pr->start, pr->end, pr->flags); /* We'll assign a new address later */ r->end -= r->start; r->start = 0; @@ -276,20 +290,12 @@ pcibios_allocate_resources(int pass) pci_for_each_dev(dev) { pci_read_config_word(dev, PCI_COMMAND, &command); - for(idx = 0; idx < 6; idx++) { + for (idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; if (r->parent) /* Already allocated */ continue; if (!r->start) /* Not assigned at all */ continue; - if (r->end == 0xffffffff) { - /* LongTrail OF quirk: unassigned */ - DBG("PCI: Resource %08lx-%08lx was unassigned\n", r->start, r->end); - r->end -= r->start; - r->start = 0; - continue; - } - if (r->flags & IORESOURCE_IO) disabled = !(command & PCI_COMMAND_IO); else @@ -306,7 +312,8 @@ pcibios_allocate_resources(int pass) DBG("PCI: Switching off ROM of %s\n", dev->slot_name); r->flags &= ~PCI_ROM_ADDRESS_ENABLE; pci_read_config_dword(dev, dev->rom_base_reg, ®); - pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE); + pci_write_config_dword(dev, dev->rom_base_reg, + reg & ~PCI_ROM_ADDRESS_ENABLE); } } } @@ -325,21 +332,14 @@ pcibios_assign_resources(void) if (!class || class == PCI_CLASS_BRIDGE_HOST) continue; - for(idx=0; idx<6; idx++) { + for (idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; -#if 0 /* we don't need this PC-ism */ - /* - * Don't touch IDE controllers and I/O ports of video cards! - */ - if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) || - (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO))) - continue; -#endif /* - * We shall assign a new address to this resource, either because - * the BIOS (sic) forgot to do so or because we have decided the old - * address was unusable for some reason. + * We shall assign a new address to this resource, + * either because the BIOS (sic) forgot to do so + * or because we have decided the old address was + * unusable for some reason. */ if (!r->start && r->end && (!ppc_md.pcibios_enable_device_hook || @@ -347,13 +347,13 @@ pcibios_assign_resources(void) pci_assign_resource(dev, idx); } - if (0) { /* don't assign ROMs */ - r = &dev->resource[PCI_ROM_RESOURCE]; - r->end -= r->start; - r->start = 0; - if (r->end) - pci_assign_resource(dev, PCI_ROM_RESOURCE); - } +#if 0 /* don't assign ROMs */ + r = &dev->resource[PCI_ROM_RESOURCE]; + r->end -= r->start; + r->start = 0; + if (r->end) + pci_assign_resource(dev, PCI_ROM_RESOURCE); +#endif } } @@ -496,10 +496,15 @@ scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) && ((reg[0] >> 16) & 0xff) == bus) return node; - /* For PCI<->PCI bridges or CardBus bridges, we go down */ + /* For PCI<->PCI bridges or CardBus bridges, we go down + * Note: some OFs create a parent node "multifunc-device" as + * a fake root for all functions of a multi-function device, + * we go down them as well. + */ class_code = (unsigned int *) get_property(node, "class-code", 0); - if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && - (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) + if ((!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && + (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) && + strcmp(node->name, "multifunc-device")) continue; sub_node = scan_OF_childs_for_device(node->child, bus, dev_fn); if (sub_node) @@ -682,9 +687,9 @@ pcibios_init(void) { struct pci_controller *hose; struct pci_bus *bus; - int next_busno, i; + int next_busno; - printk("PCI: Probing PCI hardware\n"); + printk(KERN_INFO "PCI: Probing PCI hardware\n"); /* Scan all of the recorded PCI controllers. */ for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { @@ -692,18 +697,6 @@ pcibios_init(void) hose->first_busno = next_busno; hose->last_busno = 0xff; bus = pci_scan_bus(hose->first_busno, hose->ops, hose); - if (hose->io_resource.flags) { - unsigned long offs; - - offs = (unsigned long)hose->io_base_virt - isa_io_base; - hose->io_resource.start += offs; - hose->io_resource.end += offs; - bus->resource[0] = &hose->io_resource; - } - for (i = 0; i < 3; ++i) - if (hose->mem_resources[i].flags) - bus->resource[i+1] = &hose->mem_resources[i]; - hose->bus = bus; hose->last_busno = bus->subordinate; if (pci_assign_all_busses || next_busno <= hose->last_busno) next_busno = hose->last_busno+1; @@ -716,7 +709,7 @@ pcibios_init(void) */ if (pci_assign_all_busses && have_of) pcibios_make_OF_bus_map(); - + /* Call machine dependant fixup */ if (ppc_md.pcibios_fixup) ppc_md.pcibios_fixup(); @@ -727,27 +720,7 @@ pcibios_init(void) pcibios_allocate_resources(1); pcibios_assign_resources(); -#ifdef CONFIG_BLK_DEV_IDE - /* OF fails to initialize IDE controllers on macs - * (and maybe other machines) - * - * Ideally, this should be moved to the IDE layer, but we need - * to check specifically with Andre Hedrick how to do it cleanly - * since the common IDE code seem to care about the fact that the - * BIOS may have disabled a controller. - * - * -- BenH - */ - if (_machine == _MACH_Pmac) { - struct pci_dev *dev; - pci_for_each_dev(dev) - { - if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE) - pci_enable_device(dev); - } - } -#endif /* CONFIG_BLK_DEV_IDE */ - + /* Call machine dependent post-init code */ if (ppc_md.pcibios_after_init) ppc_md.pcibios_after_init(); } @@ -775,21 +748,62 @@ unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, void __init pcibios_fixup_bus(struct pci_bus *bus) { - struct pci_controller *hose; + struct pci_controller *hose = (struct pci_controller *) bus->sysdata; + unsigned long io_offset; + struct resource *res; + int i; - pci_read_bridge_bases(bus); + io_offset = (unsigned long)hose->io_base_virt - isa_io_base; + if (bus->parent == NULL) { + /* This is a host bridge - fill in its resources */ + hose->bus = bus; - hose = pci_bus_to_hose(bus->number); + bus->resource[0] = res = &hose->io_resource; + if (!res->flags) { + if (io_offset) + printk(KERN_ERR "I/O resource not set for host" + " bridge %d\n", hose->index); + res->start = 0; + res->end = IO_SPACE_LIMIT; + res->flags = IORESOURCE_IO; + } + res->start += io_offset; + res->end += io_offset; + + for (i = 0; i < 3; ++i) { + res = &hose->mem_resources[i]; + if (!res->flags) { + if (i > 0) + continue; + printk(KERN_ERR "Memory resource not set for " + "host bridge %d\n", hose->index); + res->start = hose->pci_mem_offset; + res->end = ~0U; + res->flags = IORESOURCE_MEM; + } + bus->resource[i+1] = res; + } + } else { + /* This is a subordinate bridge */ + pci_read_bridge_bases(bus); - /* Apply pci_mem_offset to bridge mem resource */ - if (hose->first_busno != bus->number) - if (bus->resource[1]->start && (bus->resource[1]->end != -1)) - { - bus->resource[1]->start += hose->pci_mem_offset; - bus->resource[1]->end += hose->pci_mem_offset; + for (i = 0; i < 4; ++i) { + if ((res = bus->resource[i]) == NULL) + continue; + if (!res->flags) + continue; + if (io_offset && (res->flags & IORESOURCE_IO)) { + res->start += io_offset; + res->end += io_offset; + } else if (hose->pci_mem_offset + && (res->flags & IORESOURCE_MEM)) { + res->start += hose->pci_mem_offset; + res->end += hose->pci_mem_offset; + } } + } - if ( ppc_md.pcibios_fixup_bus ) + if (ppc_md.pcibios_fixup_bus) ppc_md.pcibios_fixup_bus(bus); } @@ -881,26 +895,17 @@ pci_bus_mem_base_phys(unsigned int bus) return hose->pci_mem_offset; } -#ifdef CONFIG_POWER4 -extern unsigned long pci_address_offset(int, unsigned int); -#endif /* CONFIG_POWER4 */ - unsigned long pci_resource_to_bus(struct pci_dev *pdev, struct resource *res) { /* Hack alert again ! See comments in chrp_pci.c */ -#ifdef CONFIG_POWER4 - unsigned long offset = pci_address_offset(pdev->bus->number, res->flags); - return res->start - offset; -#else /* CONFIG_POWER4 */ struct pci_controller* hose = (struct pci_controller *)pdev->sysdata; if (hose && res->flags & IORESOURCE_MEM) return res->start - hose->pci_mem_offset; /* We may want to do something with IOs here... */ return res->start; -#endif } /* @@ -1072,27 +1077,19 @@ phys_to_bus(unsigned long pa) unsigned long pci_phys_to_bus(unsigned long pa, int busnr) { -#ifdef CONFIG_POWER4 - return pa - pci_address_offset(busnr, IORESOURCE_MEM); -#else /* CONFIG_POWER4 */ struct pci_controller* hose = pci_bus_to_hose(busnr); if (!hose) return pa; return pa - hose->pci_mem_offset; -#endif } unsigned long pci_bus_to_phys(unsigned int ba, int busnr) { -#ifdef CONFIG_POWER4 - return ba + pci_address_offset(dev->bus->number, IORESOURCE_MEM); -#else /* CONFIG_POWER4 */ struct pci_controller* hose = pci_bus_to_hose(busnr); if (!hose) return ba; return ba + hose->pci_mem_offset; -#endif } /* Provide information on locations of various I/O regions in physical diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c index 6a065e726c7a..158ba13bbaf9 100644 --- a/arch/ppc/kernel/pmac_pci.c +++ b/arch/ppc/kernel/pmac_pci.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pmac_pci.c 1.14 05/17/01 18:14:21 cort + * BK Id: SCCS/s.pmac_pci.c 1.18 07/01/01 12:23:31 trini */ /* * Support for PCI bridges found on Power Macintoshes. @@ -42,8 +42,6 @@ static int has_uninorth; /* * Magic constants for enabling cache coherency in the bandit/PSX bridge. */ -#define APPLE_VENDID 0x106b -#define BANDIT_DEVID 1 #define BANDIT_DEVID_2 8 #define BANDIT_REVID 3 @@ -97,12 +95,17 @@ fixup_bus_range(struct device_node *bridge) } /* - * Apple MacRISC (UniNorth, Bandit) PCI controllers. + * Apple MacRISC (UniNorth, Bandit, Chaos) PCI controllers. * * The "Bandit" version is present in all early PCI PowerMacs, * and up to the first ones using Grackle. Some machines may * have 2 bandit controllers (2 PCI busses). * + * "Chaos" is used in some "Bandit"-type machines as a bridge + * for the separate display bus. It is accessed the same + * way as bandit, but cannot be probed for devices. It therefore + * has its own config access functions. + * * The "UniNorth" version is present in all Core99 machines * (iBook, G4, new IMacs, and all the recent Apple machines). * It contains 3 controllers in one ASIC. @@ -124,10 +127,6 @@ macrisc_cfg_access(struct pci_controller* hose, u8 bus, u8 dev_fn, u8 offset) { unsigned int caddr; -#ifdef DEBUG -// printk("macrisc_config_access(hose: 0x%08lx, bus: 0x%x, devfb: 0x%x, offset: 0x%x)\n", -// hose, bus, dev_fn, offset); -#endif if (bus == hose->first_busno) { if (dev_fn < (11 << 3)) return 0; @@ -189,55 +188,50 @@ static struct pci_ops macrisc_pci_ops = macrisc_write_config_dword }; - /* - * Apple "Chaos" PCI controller. - * - * This controller is present on some first generation "PowerSurge" - * machines (8500, 8600, ...). It's a very weird beast and will die - * in flames if we try to probe the config space. - * The long-term solution is to provide a config space "emulation" - * based on what we find in OF device tree + * Verifiy that a specific (bus, dev_fn) exists on chaos */ - -static int chaos_config_read_byte(struct pci_dev *dev, int offset, u8 *val) -{ - return PCIBIOS_DEVICE_NOT_FOUND; -} - -static int chaos_config_read_word(struct pci_dev *dev, int offset, u16 *val) -{ - return PCIBIOS_DEVICE_NOT_FOUND; -} - -static int chaos_config_read_dword(struct pci_dev *dev, int offset, u32 *val) -{ - return PCIBIOS_DEVICE_NOT_FOUND; -} - -static int chaos_config_write_byte(struct pci_dev *dev, int offset, u8 val) +static int __pmac +chaos_validate_dev(struct pci_dev *dev, int offset) { - return PCIBIOS_DEVICE_NOT_FOUND; + if(pci_device_to_OF_node(dev) == 0) + return PCIBIOS_DEVICE_NOT_FOUND; + if((dev->vendor == 0x106b) && (dev->device == 3) && (offset >= 0x10) && + (offset != 0x14) && (offset != 0x18) && (offset <= 0x24)) { + return PCIBIOS_BAD_REGISTER_NUMBER; + } + return PCIBIOS_SUCCESSFUL; } -static int chaos_config_write_word(struct pci_dev *dev, int offset, u16 val) -{ - return PCIBIOS_DEVICE_NOT_FOUND; +#define CHAOS_PCI_OP(rw, size, type) \ +static int __pmac \ +chaos_##rw##_config_##size(struct pci_dev *dev, int off, type val) \ +{ \ + int result = chaos_validate_dev(dev, off); \ + if(result == PCIBIOS_BAD_REGISTER_NUMBER) { \ + cfg_##rw##_bad(val, size) \ + return PCIBIOS_BAD_REGISTER_NUMBER; \ + } \ + if(result == PCIBIOS_SUCCESSFUL) \ + return macrisc_##rw##_config_##size(dev, off, val); \ + return result; \ } -static int chaos_config_write_dword(struct pci_dev *dev, int offset, u32 val) -{ - return PCIBIOS_DEVICE_NOT_FOUND; -} +CHAOS_PCI_OP(read, byte, u8 *) +CHAOS_PCI_OP(read, word, u16 *) +CHAOS_PCI_OP(read, dword, u32 *) +CHAOS_PCI_OP(write, byte, u8) +CHAOS_PCI_OP(write, word, u16) +CHAOS_PCI_OP(write, dword, u32) static struct pci_ops chaos_pci_ops = { - chaos_config_read_byte, - chaos_config_read_word, - chaos_config_read_dword, - chaos_config_write_byte, - chaos_config_write_word, - chaos_config_write_dword + chaos_read_config_byte, + chaos_read_config_word, + chaos_read_config_dword, + chaos_write_config_byte, + chaos_write_config_word, + chaos_write_config_dword }; @@ -245,7 +239,8 @@ static struct pci_ops chaos_pci_ops = * For a bandit bridge, turn on cache coherency if necessary. * N.B. we could clean this up using the hose ops directly. */ -static void __init init_bandit(struct pci_controller *bp) +static void __init +init_bandit(struct pci_controller *bp) { unsigned int vendev, magic; int rev; @@ -254,7 +249,8 @@ static void __init init_bandit(struct pci_controller *bp) out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID); udelay(2); vendev = in_le32((volatile unsigned int *)bp->cfg_data); - if (vendev == (BANDIT_DEVID << 16) + APPLE_VENDID) { + if (vendev == (PCI_VENDOR_ID_APPLE_BANDIT << 16) + + PCI_VENDOR_ID_APPLE) { /* read the revision id */ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID); @@ -264,7 +260,7 @@ static void __init init_bandit(struct pci_controller *bp) printk(KERN_WARNING "Unknown revision %d for bandit at %08lx\n", rev, bp->io_base_phys); - } else if (vendev != (BANDIT_DEVID_2 << 16) + APPLE_VENDID) { + } else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) { printk(KERN_WARNING "bandit isn't? (%x)\n", vendev); return; } @@ -426,7 +422,8 @@ setup_grackle(struct pci_controller *hose, unsigned io_space_size) * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise, * if we have one or more bandit or chaos bridges, we don't have a MPC106. */ -static void __init add_bridges(struct device_node *dev) +static void __init +add_bridges(struct device_node *dev) { int len; struct pci_controller *hose; @@ -490,17 +487,11 @@ static void __init add_bridges(struct device_node *dev) } } -static void +static void __init pcibios_fixup_OF_interrupts(void) { struct pci_dev* dev; - /* - * FIXME: This is broken: We should not assign IRQ's to IRQless - * devices (look at PCI_INTERRUPT_PIN) and we also should - * honor the existence of multi-function devices where - * different functions have different interrupt pins. [mj] - */ pci_for_each_dev(dev) { /* @@ -533,7 +524,7 @@ pmac_pcibios_fixup(void) pcibios_fixup_OF_interrupts(); } -int +int __pmac pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) { struct device_node* node; @@ -563,11 +554,30 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) /* We power down some devices after they have been probed. They'll * be powered back on later on */ -void +void __init pmac_pcibios_after_init(void) { struct device_node* nd; +#ifdef CONFIG_BLK_DEV_IDE + struct pci_dev *dev; + + /* OF fails to initialize IDE controllers on macs + * (and maybe other machines) + * + * Ideally, this should be moved to the IDE layer, but we need + * to check specifically with Andre Hedrick how to do it cleanly + * since the common IDE code seem to care about the fact that the + * BIOS may have disabled a controller. + * + * -- BenH + */ + pci_for_each_dev(dev) { + if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE) + pci_enable_device(dev); + } +#endif /* CONFIG_BLK_DEV_IDE */ + nd = find_devices("firewire"); while (nd) { if (nd->parent && device_is_compatible(nd, "pci106b,18") diff --git a/arch/ppc/kernel/ppc4xx_pic.h b/arch/ppc/kernel/ppc4xx_pic.h index b1feacab9f45..ebb63a7f36d4 100644 --- a/arch/ppc/kernel/ppc4xx_pic.h +++ b/arch/ppc/kernel/ppc4xx_pic.h @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc4xx_pic.h 1.5 05/17/01 18:14:21 cort + * BK Id: SCCS/s.ppc4xx_pic.h 1.8 06/15/01 13:56:56 paulus */ /* * @@ -14,12 +14,8 @@ #ifndef __PPC4XX_PIC_H__ #define __PPC4XX_PIC_H__ -#include <asm/ptrace.h> - - -#ifdef __cplusplus -extern "C" { -#endif +#include <linux/config.h> +#include "local_irq.h" /* External Global Variables */ @@ -31,9 +27,4 @@ extern struct hw_interrupt_type *ppc4xx_pic; extern void ppc4xx_pic_init(void); extern int ppc4xx_pic_get_irq(struct pt_regs *regs); - -#ifdef __cplusplus -} -#endif - #endif /* __PPC4XX_PIC_H__ */ diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c index 1a51a954f72a..8bdf4a52df53 100644 --- a/arch/ppc/kernel/ppc_htab.c +++ b/arch/ppc/kernel/ppc_htab.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc_htab.c 1.8 05/17/01 18:14:21 cort + * BK Id: SCCS/s.ppc_htab.c 1.11 06/28/01 15:50:16 paulus */ /* * PowerPC hash table management proc entry. Will show information @@ -41,9 +41,12 @@ extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; extern unsigned long _SDR1; extern unsigned long htab_reloads; +extern unsigned long htab_preloads; extern unsigned long htab_evicts; extern unsigned long pte_misses; extern unsigned long pte_errors; +extern unsigned int primary_pteg_full; +extern unsigned int htab_hash_searches; /* these will go into processor.h when I'm done debugging -- Cort */ #define MMCR0 952 @@ -110,7 +113,7 @@ static ssize_t ppc_htab_read(struct file * file, char * buf, { unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0; int n = 0, valid; - unsigned int kptes = 0, overflow = 0, uptes = 0, zombie_ptes = 0; + unsigned int kptes = 0, uptes = 0, zombie_ptes = 0; PTE *ptr; struct task_struct *p; char buffer[512]; @@ -150,41 +153,34 @@ static ssize_t ppc_htab_read(struct file * file, char * buf, n += sprintf( buffer + n, "No Hash Table used\n"); goto return_string; } - - /* - * compute user/kernel pte's table this info can be - * misleading since there can be valid (v bit set) entries - * in the table but their vsid is used by no process (mm->context) - * due to the way tlb invalidation is handled on the ppc - * -- Cort - */ + +#if !defined(CONFIG_8xx) && !defined(CONFIG_4xx) for ( ptr = Hash ; ptr < Hash_end ; ptr++) { - if (ptr->v) - { - /* make sure someone is using this context/vsid */ - valid = 0; - for_each_task(p) - { - if (p->mm && (ptr->vsid >> 4) == p->mm->context) - { - valid = 1; - break; - } - } - if ( !valid ) - { - zombie_ptes++; - continue; - } - /* user not allowed read or write */ - if (ptr->pp == PP_RWXX) - kptes++; - else + unsigned int ctx, mctx, vsid; + + if (!ptr->v) + continue; + /* make sure someone is using this context/vsid */ + /* first undo the esid skew */ + vsid = ptr->vsid; + mctx = ((vsid - (vsid & 0xf) * 0x111) >> 4) & 0xfffff; + if (mctx == 0) { + kptes++; + continue; + } + /* now undo the context skew; 801921 * 897 == 1 mod 2^20 */ + ctx = (mctx * 801921) & 0xfffff; + valid = 0; + for_each_task(p) { + if (p->mm != NULL && ctx == p->mm->context) { + valid = 1; uptes++; - if (ptr->h == 1) - overflow++; + break; + } } + if (!valid) + zombie_ptes++; } n += sprintf( buffer + n, @@ -195,29 +191,32 @@ static ssize_t ppc_htab_read(struct file * file, char * buf, "Entries\t\t: %lu\n" "User ptes\t: %u\n" "Kernel ptes\t: %u\n" - "Overflows\t: %u\n" "Zombies\t\t: %u\n" - "Percent full\t: %%%lu\n", + "Percent full\t: %lu%%\n", (unsigned long)(Hash_size>>10), (Hash_size/(sizeof(PTE)*8)), (unsigned long)Hash, Hash_size/sizeof(PTE), uptes, kptes, - overflow, zombie_ptes, ((kptes+uptes)*100) / (Hash_size/sizeof(PTE)) ); n += sprintf( buffer + n, - "Reloads\t\t: %08lx\n" - "Evicts\t\t: %08lx\n", - htab_reloads, htab_evicts); + "Reloads\t\t: %lu\n" + "Preloads\t: %lu\n" + "Searches\t: %u\n" + "Overflows\t: %u\n" + "Evicts\t\t: %lu\n", + htab_reloads, htab_preloads, htab_hash_searches, + primary_pteg_full, htab_evicts); +#endif /* !8xx && !4xx */ return_string: n += sprintf( buffer + n, - "Non-error misses: %08lx\n" - "Error misses\t: %08lx\n", + "Non-error misses: %lu\n" + "Error misses\t: %lu\n", pte_misses, pte_errors); if (*ppos >= strlen(buffer)) return 0; diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 87ced4dab22a..8967c26551d1 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc_ksyms.c 1.34 06/09/01 22:38:13 paulus + * BK Id: SCCS/s.ppc_ksyms.c 1.36 06/28/01 15:50:16 paulus */ #include <linux/config.h> #include <linux/module.h> @@ -359,11 +359,10 @@ EXPORT_SYMBOL(cpm_free_handler); EXPORT_SYMBOL(ret_to_user_hook); EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(set_context); -EXPORT_SYMBOL(mmu_context_overflow); -EXPORT_SYMBOL(flush_hash_page); /* For MOL */ EXPORT_SYMBOL(handle_mm_fault); /* For MOL */ EXPORT_SYMBOL_NOVERS(disarm_decr); #if !defined(CONFIG_8xx) && !defined(CONFIG_4xx) +EXPORT_SYMBOL(flush_hash_page); /* For MOL */ extern long *intercept_table; EXPORT_SYMBOL(intercept_table); #endif diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 1936e0ec4e7a..e922cac895e1 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.process.c 1.15 05/17/01 18:14:22 cort + * BK Id: SCCS/s.process.c 1.19 06/15/01 13:56:56 paulus */ /* * linux/arch/ppc/kernel/process.c @@ -267,6 +267,15 @@ void show_regs(struct pt_regs * regs) printk("Last syscall: %ld ", current->thread.last_syscall); printk("\nlast math %p last altivec %p", last_task_used_math, last_task_used_altivec); + +#ifdef CONFIG_4xx + printk("\nPLB0: bear= 0x%8.8x acr= 0x%8.8x besr= 0x%8.8x\n", + mfdcr(DCRN_POB0_BEAR), mfdcr(DCRN_PLB0_ACR), + mfdcr(DCRN_PLB0_BESR)); + printk("PLB0 to OPB: bear= 0x%8.8x besr0= 0x%8.8x besr1= 0x%8.8x\n", + mfdcr(DCRN_PLB0_BEAR), mfdcr(DCRN_POB0_BESR0), + mfdcr(DCRN_POB0_BESR1)); +#endif #ifdef CONFIG_SMP printk(" CPU: %d", current->processor); @@ -289,7 +298,8 @@ void show_regs(struct pt_regs * regs) printk("\n"); } } -out: ; +out: + print_backtrace((unsigned long *)regs->gpr[1]); } void exit_thread(void) diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index f049ea79303a..5ea759857a2c 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.prom.c 1.23 06/06/01 22:49:01 paulus + * BK Id: SCCS/s.prom.c 1.26 06/28/01 15:50:16 paulus */ /* * Procedures for interfacing to the Open Firmware PROM on @@ -174,7 +174,6 @@ static void prom_welcome(boot_infos_t* bi, unsigned long phys); #endif extern void enter_rtas(void *); -extern unsigned long reloc_offset(void); void phys_call_rtas(int, int, int, ...); extern char cmd_line[512]; /* XXX */ @@ -192,6 +191,14 @@ unsigned long dev_tree_size; #define BOOT_INFO_IS_V2_COMPATIBLE(bi) ((bi)->version >= 2) #define BOOT_INFO_IS_V4_COMPATIBLE(bi) ((bi)->version >= 4) +/* + * Note that prom_init() and anything called from prom_init() must + * use the RELOC/PTRRELOC macros to access any static data in + * memory, since the kernel may be running at an address that is + * different from the address that it was linked at. + * (Note that strings count as static variables.) + */ + __init static void prom_exit() @@ -480,13 +487,14 @@ static inline void make_pte(unsigned long htab, unsigned int hsize, unsigned int va, unsigned int pa, int mode) { unsigned int *pteg; - unsigned int hash, i; + unsigned int hash, i, vsid; - hash = ((va >> 5) ^ (va >> 21)) & 0x7fff80; + vsid = ((va >> 28) * 0x111) << 12; + hash = ((va ^ vsid) >> 5) & 0x7fff80; pteg = (unsigned int *)(htab + (hash & (hsize - 1))); for (i = 0; i < 8; ++i, pteg += 4) { if ((pteg[1] & 1) == 0) { - pteg[1] = ((va >> 16) & 0xff80) | 1; + pteg[1] = vsid | ((va >> 16) & 0xf80) | 1; pteg[3] = pa | mode; break; } diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index b39dae8a9fec..bc27e077b248 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.setup.c 1.32 05/23/01 00:38:42 cort + * BK Id: SCCS/s.setup.c 1.44 06/28/01 08:01:06 trini */ /* * Common prep/pmac/chrp boot and setup code. @@ -36,16 +36,16 @@ #include <asm/mpc8260.h> #include <asm/immap_8260.h> #endif +#ifdef CONFIG_4xx +#include <asm/ppc4xx.h> +#endif #include <asm/bootx.h> #include <asm/machdep.h> #include <asm/feature.h> #include <asm/uaccess.h> -#ifdef CONFIG_OAK -#include "oak_setup.h" -#endif /* CONFIG_OAK */ -extern void pmac_init(unsigned long r3, +extern void apus_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, @@ -57,7 +57,7 @@ extern void chrp_init(unsigned long r3, unsigned long r6, unsigned long r7); -extern void prep_init(unsigned long r3, +extern void gemini_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, @@ -69,19 +69,24 @@ extern void m8xx_init(unsigned long r3, unsigned long r6, unsigned long r7); -extern void apus_init(unsigned long r3, +extern void m8260_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + +extern void pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7); -extern void gemini_init(unsigned long r3, +extern void prep_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7); - extern void bootx_init(unsigned long r4, unsigned long phys); extern unsigned long reloc_offset(void); @@ -332,7 +337,7 @@ int get_cpuinfo(char *buffer) * Assume here that all clock rates are the same in a * smp system. -- Cort */ -#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) && !defined(CONFIG_8260) +#if defined(CONFIG_ALL_PPC) if ( have_of ) { struct device_node *cpu_node; @@ -356,7 +361,7 @@ int get_cpuinfo(char *buffer) len += sprintf(len+buffer, "clock\t\t: %dMHz\n", *fp / 1000000); } -#endif /* !CONFIG_4xx && !CONFIG_8xx */ +#endif /* CONFIG_ALL_PPC */ if (ppc_md.setup_residual != NULL) { @@ -379,11 +384,12 @@ int get_cpuinfo(char *buffer) break; } - len += sprintf(len+buffer, "revision\t: %hd.%hd\n", maj, min); + len += sprintf(len+buffer, "revision\t: %hd.%hd (pvr %04x %04x)\n", + maj, min, PVR_VER(pvr), PVR_REV(pvr)); len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n", - (CD(loops_per_jiffy)+2500)/(500000/HZ), - (CD(loops_per_jiffy)+2500)/(5000/HZ) % 100); + CD(loops_per_jiffy)/(500000/HZ), + CD(loops_per_jiffy)/(5000/HZ) % 100); bogosum += CD(loops_per_jiffy); } @@ -391,8 +397,8 @@ int get_cpuinfo(char *buffer) if ( i ) len += sprintf(buffer+len, "\n"); len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n", - (bogosum+2500)/(500000/HZ), - (bogosum+2500)/(5000/HZ) % 100); + bogosum/(500000/HZ), + bogosum/(5000/HZ) % 100); #endif /* CONFIG_SMP */ /* @@ -441,11 +447,15 @@ intuit_machine_type(void) } #endif /* CONFIG_ALL_PPC */ -#ifdef CONFIG_6xx +#if defined(CONFIG_6xx) || defined(CONFIG_PPC64BRIDGE) /* * We're called here very early in the boot. We determine the machine * type and call the appropriate low-level setup functions. * -- Cort <cort@fsmlabs.com> + * + * Note that the kernel may be running at an address which is different + * from the address that it was linked at, so we must use RELOC/PTRRELOC + * to access static data (including strings). -- paulus */ __init unsigned long @@ -454,65 +464,36 @@ early_init(int r3, int r4, int r5) extern char __bss_start, _end; unsigned long phys; unsigned long offset = reloc_offset(); - unsigned long local_have_of = 1, local_machine; - struct bi_record *rec; - + /* Default */ phys = offset + KERNELBASE; - -#if defined(CONFIG_APUS) - return phys; -#endif - + /* First zero the BSS -- use memset, some arches don't have * caches on yet */ - memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start); + memset_io(PTRRELOC(&__bss_start), 0, &_end - &__bss_start); -#if defined(CONFIG_ALL_PPC) || defined(CONFIG_GEMINI) +#if defined(CONFIG_ALL_PPC) /* If we came here from BootX, clear the screen, * set up some pointers and return. */ -#if defined(CONFIG_ALL_PPC) if ((r3 == 0x426f6f58) && (r5 == 0)) { bootx_init(r4, phys); return phys; } -#endif /* check if we're prep, return if we are */ if ( *(unsigned long *)(0) == 0xdeadc0de ) return phys; - - /* - * See if we have any bootloader info passed along. If we do, - * get the machine type and find out if we have OF. - * - * The strategy here is to assume that we want to call prom_init() - * unless the bootinfo data passed to us tell us that we don't - * have OF. - * -- Cort <cort@fsmlabs.com> + + /* + * for now, don't use bootinfo because it breaks yaboot 0.5 + * and assume that if we didn't find a magic number, we have OF */ - rec = (struct bi_record *)_ALIGN((ulong)PTRRELOC(&__bss_start)+(1<<20)-1,(1<<20)); - if ( rec->tag == BI_FIRST ) - { - for ( ; rec->tag != BI_LAST ; - rec = (struct bi_record *)((ulong)rec + rec->size) ) - { - ulong *data = rec->data; - if ( rec->tag == BI_MACHTYPE ) - { - local_machine = data[0]; - local_have_of = data[1]; - } - } - } + phys = prom_init(r3, r4, (prom_entry)r5); +#endif - if ( local_have_of ) - phys = prom_init( r3, r4, (prom_entry)r5); -#endif - return phys; } -#endif /* CONFIG_6xx */ +#endif /* CONFIG_6xx || CONFIG_PPC64BRIDGE */ /* * Find out what kind of machine we're on and save any data we need @@ -522,6 +503,10 @@ unsigned long __init identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { +#ifdef CONFIG_CMDLINE + strcpy(cmd_line, CONFIG_CMDLINE); +#endif /* CONFIG_CMDLINE */ + parse_bootinfo(); if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100); @@ -809,7 +794,7 @@ void __init setup_arch(char **cmdline_p) ppc_md.setup_arch(); if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); -#ifdef CONFIG_PCI +#if defined(CONFIG_PCI) && defined(CONFIG_ALL_PPC) /* We create the "pci-OF-bus-map" property now so it appear in the * /proc device tree */ @@ -825,7 +810,7 @@ void __init setup_arch(char **cmdline_p) prom_add_property(find_path_device("/"), of_prop); } } -#endif /* CONFIG_PCI */ +#endif /* CONFIG_PCI && CONFIG_ALL_PPC */ paging_init(); sort_exception_table(); diff --git a/arch/ppc/kernel/sleep.S b/arch/ppc/kernel/sleep.S index 8d4b7fc9c301..428aa01ffc19 100644 --- a/arch/ppc/kernel/sleep.S +++ b/arch/ppc/kernel/sleep.S @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.sleep.S 1.7 05/17/01 18:14:22 cort + * BK Id: SCCS/s.sleep.S 1.10 06/28/01 15:50:17 paulus */ /* * This file contains sleep low-level functions for PowerBook G3. @@ -194,7 +194,7 @@ wake_up: lis r3,0x2000 /* Ku = 1, VSID = 0 */ li r4,0 3: mtsrin r3,r4 - addi r3,r3,1 /* increment VSID */ + addi r3,r3,0x111 /* increment VSID */ addis r4,r4,0x1000 /* address of next segment */ bdnz 3b diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index a104ee2127fe..896cc822da78 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.traps.c 1.11 05/17/01 18:14:22 cort + * BK Id: SCCS/s.traps.c 1.14 06/15/01 13:00:20 paulus */ /* * linux/arch/ppc/kernel/traps.c @@ -82,7 +82,6 @@ void die(const char * str, struct pt_regs * fp, long err) spin_lock_irq(&oops_lock); printk("Oops: %s, sig: %ld\n", str, err); show_regs(fp); - print_backtrace((unsigned long *)fp->gpr[1]); spin_unlock_irq(&oops_lock); /* do_exit() should take care of panic'ing from an interrupt * context so we don't handle it here @@ -186,7 +185,6 @@ SMIException(struct pt_regs *regs) } #endif show_regs(regs); - print_backtrace((unsigned long *)regs->gpr[1]); panic("System Management Interrupt"); } @@ -334,7 +332,6 @@ StackOverflow(struct pt_regs *regs) debugger(regs); #endif show_regs(regs); - print_backtrace((unsigned long *)regs->gpr[1]); panic("kernel stack overflow"); } diff --git a/arch/ppc/mm/Makefile b/arch/ppc/mm/Makefile index 4a94cbd8055f..fe41ea3428c4 100644 --- a/arch/ppc/mm/Makefile +++ b/arch/ppc/mm/Makefile @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:23 cort +# BK Id: SCCS/s.Makefile 1.6 06/28/01 15:50:17 paulus # # # Makefile for the linux ppc-specific parts of the memory manager. @@ -9,9 +9,21 @@ # # Note 2! The CFLAGS definition is now in the main makefile... +USE_STANDARD_AS_RULE := true + +ifdef CONFIG_PPC64BRIDGE +EXTRA_AFLAGS := -Wa,-mppc64bridge +endif + O_TARGET := mm.o obj-y := fault.o init.o mem_pieces.o extable.o +ifneq ($(CONFIG_8xx),y) +ifneq ($(CONFIG_4xx),y) +obj-y += hashtable.o +endif +endif + obj-$(CONFIG_4xx) += 4xx_tlb.o include $(TOPDIR)/Rules.make diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c index bba417366605..657bd0344971 100644 --- a/arch/ppc/mm/fault.c +++ b/arch/ppc/mm/fault.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fault.c 1.10 05/17/01 18:14:23 cort + * BK Id: SCCS/s.fault.c 1.13 06/28/01 15:50:17 paulus */ /* * arch/ppc/mm/fault.c @@ -44,11 +44,12 @@ extern int (*debugger_dabr_match)(struct pt_regs *); int debugger_kernel_faults = 1; #endif -unsigned long htab_reloads = 0; /* updated by head.S:hash_page() */ -unsigned long htab_evicts = 0; /* updated by head.S:hash_page() */ -unsigned long pte_misses = 0; /* updated by do_page_fault() */ -unsigned long pte_errors = 0; /* updated by do_page_fault() */ -unsigned int probingmem = 0; +unsigned long htab_reloads; /* updated by hashtable.S:hash_page() */ +unsigned long htab_evicts; /* updated by hashtable.S:hash_page() */ +unsigned long htab_preloads; /* updated by hashtable.S:add_hash_page() */ +unsigned long pte_misses; /* updated by do_page_fault() */ +unsigned long pte_errors; /* updated by do_page_fault() */ +unsigned int probingmem; extern void die_if_kernel(char *, struct pt_regs *, long); void bad_page_fault(struct pt_regs *, unsigned long, int sig); diff --git a/arch/ppc/mm/hashtable.S b/arch/ppc/mm/hashtable.S new file mode 100644 index 000000000000..157f4454b499 --- /dev/null +++ b/arch/ppc/mm/hashtable.S @@ -0,0 +1,627 @@ +/* + * BK Id: SCCS/s.hashtable.S 1.16 06/29/01 08:51:52 paulus + */ +/* + * arch/ppc/kernel/hashtable.S + * + * $Id: hashtable.S,v 1.6 1999/10/08 01:56:15 paulus Exp $ + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * + * This file contains low-level assembler routines for managing + * the PowerPC MMU hash table. (PPC 8xx processors don't use a + * hash table, so this file is not used on them.) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include <linux/config.h> +#include "../kernel/ppc_asm.h" +#include <asm/processor.h> +#include <asm/page.h> +#include <asm/pgtable.h> + +#ifdef CONFIG_SMP + .comm hash_table_lock,4 +#endif /* CONFIG_SMP */ + +/* + * Load a PTE into the hash table, if possible. + * The address is in r4, and r3 contains an access flag: + * _PAGE_RW (0x400) if a write. + * r23 contains the SRR1 value, from which we use the MSR_PR bit. + * SPRG3 contains the physical address of the current task's thread. + * + * Returns to the caller if the access is illegal or there is no + * mapping for the address. Otherwise it places an appropriate PTE + * in the hash table and returns from the exception. + * Uses r0, r2 - r7, ctr, lr. + */ + .text + .globl hash_page +hash_page: +#ifdef CONFIG_PPC64BRIDGE + mfmsr r0 + clrldi r0,r0,1 /* make sure it's in 32-bit mode */ + MTMSRD(r0) + isync +#endif + tophys(r7,0) /* gets -KERNELBASE into r7 */ +#ifdef CONFIG_SMP + addis r2,r7,hash_table_lock@h + ori r2,r2,hash_table_lock@l + mfspr r5,SPRG3 + lwz r0,PROCESSOR-THREAD(r5) + oris r0,r0,0x0fff + b 10f +11: lwz r6,0(r2) + cmpwi 0,r6,0 + bne 11b +10: lwarx r6,0,r2 + cmpwi 0,r6,0 + bne- 11b + stwcx. r0,0,r2 + bne- 10b + isync +#endif + /* Get PTE (linux-style) and check access */ + lis r0,KERNELBASE@h /* check if kernel address */ + cmplw 0,r4,r0 + mfspr r2,SPRG3 /* current task's THREAD (phys) */ + ori r3,r3,_PAGE_USER|_PAGE_PRESENT /* test low addresses as user */ + lwz r5,PGDIR(r2) /* virt page-table root */ + blt+ 112f /* assume user more likely */ + lis r5,swapper_pg_dir@ha /* if kernel address, use */ + addi r5,r5,swapper_pg_dir@l /* kernel page table */ + rlwimi r3,r23,32-12,29,29 /* MSR_PR -> _PAGE_USER */ +112: add r5,r5,r7 /* convert to phys addr */ + rlwimi r5,r4,12,20,29 /* insert top 10 bits of address */ + lwz r5,0(r5) /* get pmd entry */ + rlwinm. r5,r5,0,0,19 /* extract address of pte page */ +#ifdef CONFIG_SMP + beq- hash_page_out /* return if no mapping */ +#else + /* XXX it seems like the 601 will give a machine fault on the + rfi if its alignment is wrong (bottom 4 bits of address are + 8 or 0xc) and we have had a not-taken conditional branch + to the address following the rfi. */ + beqlr- +#endif + add r2,r5,r7 /* convert to phys addr */ + rlwimi r2,r4,22,20,29 /* insert next 10 bits of address */ + rlwinm r0,r3,32-3,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */ + ori r0,r0,_PAGE_ACCESSED|_PAGE_HASHPTE + + /* + * Update the linux PTE atomically. We do the lwarx up-front + * because almost always, there won't be a permission violation + * and there won't already be an HPTE, and thus we will have + * to update the PTE to set _PAGE_HASHPTE. -- paulus. + */ +retry: + lwarx r6,0,r2 /* get linux-style pte */ + andc. r5,r3,r6 /* check access & ~permission */ +#ifdef CONFIG_SMP + bne- hash_page_out /* return if access not permitted */ +#else + bnelr- +#endif + or r5,r0,r6 /* set accessed/dirty bits */ + stwcx. r5,0,r2 /* attempt to update PTE */ + bne- retry /* retry if someone got there first */ + + mfsrin r3,r4 /* get segment reg for segment */ + mr r2,r8 /* we have saved r2 but not r8 */ + bl create_hpte /* add the hash table entry */ + mr r8,r2 + +/* + * htab_reloads counts the number of times we have to fault an + * HPTE into the hash table. This should only happen after a + * fork (because fork does a flush_tlb_mm) or a vmalloc or ioremap. + * Where a page is faulted into a process's address space, + * update_mmu_cache gets called to put the HPTE into the hash table + * and those are counted as preloads rather than reloads. + */ + addis r2,r7,htab_reloads@ha + lwz r3,htab_reloads@l(r2) + addi r3,r3,1 + stw r3,htab_reloads@l(r2) + +#ifdef CONFIG_SMP + eieio + addis r2,r7,hash_table_lock@ha + li r0,0 + stw r0,hash_table_lock@l(r2) +#endif + + /* Return from the exception */ + lwz r3,_CCR(r21) + lwz r4,_LINK(r21) + lwz r5,_CTR(r21) + mtcrf 0xff,r3 + mtlr r4 + mtctr r5 + lwz r0,GPR0(r21) + lwz r1,GPR1(r21) + lwz r2,GPR2(r21) + lwz r3,GPR3(r21) + lwz r4,GPR4(r21) + lwz r5,GPR5(r21) + lwz r6,GPR6(r21) + lwz r7,GPR7(r21) + /* we haven't used xer */ + mtspr SRR1,r23 + mtspr SRR0,r22 + lwz r20,GPR20(r21) + lwz r22,GPR22(r21) + lwz r23,GPR23(r21) + lwz r21,GPR21(r21) + RFI + +#ifdef CONFIG_SMP +hash_page_out: + eieio + addis r2,r7,hash_table_lock@ha + li r0,0 + stw r0,hash_table_lock@l(r2) + blr +#endif /* CONFIG_SMP */ + +/* + * Add an entry for a particular page to the hash table. + * + * add_hash_page(unsigned context, unsigned long va, pte_t pte) + * + * We assume any necessary modifications to the pte (e.g. setting + * the accessed bit) have already been done and that there is actually + * a hash table in use (i.e. we're not on a 603). + */ +_GLOBAL(add_hash_page) + mflr r0 + stw r0,4(r1) + + /* Convert context and va to VSID */ + mulli r3,r3,897*16 /* multiply context by context skew */ + rlwinm r0,r4,4,28,31 /* get ESID (top 4 bits of va) */ + mulli r0,r0,0x111 /* multiply by ESID skew */ + add r3,r3,r0 /* note create_hpte trims to 24 bits */ + + /* + * We disable interrupts here, even on UP, because we don't + * want to race with hash_page, and because we want the + * _PAGE_HASHPTE bit to be a reliable indication of whether + * the HPTE exists (or at least whether one did once). -- paulus + */ + mfmsr r10 + SYNC + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + mtmsr r0 + SYNC + +#ifdef CONFIG_SMP + lis r9,hash_table_lock@h + ori r9,r9,hash_table_lock@l + lwz r8,PROCESSOR(r2) + oris r8,r8,10 +10: lwarx r7,0,r9 + cmpi 0,r7,0 + bne- 11f + stwcx. r8,0,r9 + beq+ 12f +11: lwz r7,0(r9) + cmpi 0,r7,0 + beq 10b + b 11b +12: isync +#endif + + /* + * Fetch the linux pte and test and set _PAGE_HASHPTE atomically. + * If _PAGE_HASHPTE was already set, we don't replace the existing + * HPTE, so we just unlock and return. + */ + mr r7,r5 +1: lwarx r6,0,r7 + andi. r0,r6,_PAGE_HASHPTE + bne 9f /* if HASHPTE already set, done */ + ori r5,r6,_PAGE_ACCESSED|_PAGE_HASHPTE + stwcx. r5,0,r7 + bne- 1b + + li r7,0 /* no address offset needed */ + bl create_hpte + + lis r8,htab_preloads@ha + lwz r3,htab_preloads@l(r8) + addi r3,r3,1 + stw r3,htab_preloads@l(r8) + +9: +#ifdef CONFIG_SMP + eieio + li r0,0 + stw r0,0(r9) /* clear hash_table_lock */ +#endif + + lwz r0,4(r1) + mtlr r0 + + /* reenable interrupts */ + mtmsr r10 + SYNC + blr + +/* + * This routine adds a hardware PTE to the hash table. + * It is designed to be called with the MMU either on or off. + * r3 contains the VSID, r4 contains the virtual address, + * r5 contains the linux PTE, r6 contains the old value of the + * linux PTE (before setting _PAGE_HASHPTE) and r7 contains the + * offset to be added to addresses (0 if the MMU is on, + * -KERNELBASE if it is off). + * On SMP, the caller should have the hash_table_lock held. + * We assume that the caller has (or will) set the _PAGE_HASHPTE + * bit in the linux PTE in memory. The value passed in r6 should + * be the old linux PTE value; if it doesn't have _PAGE_HASHPTE set + * this routine will skip the search for an existing HPTE. + * This procedure modifies r0, r3 - r6, r8, cr0. + * -- paulus. + * + * For speed, 4 of the instructions get patched once the size and + * physical address of the hash table are known. These definitions + * of Hash_base and Hash_bits below are just an example. + */ +Hash_base = 0xc0180000 +Hash_bits = 12 /* e.g. 256kB hash table */ +Hash_msk = (((1 << Hash_bits) - 1) * 64) + +#ifndef CONFIG_PPC64BRIDGE +/* defines for the PTE format for 32-bit PPCs */ +#define PTE_SIZE 8 +#define PTEG_SIZE 64 +#define LG_PTEG_SIZE 6 +#define LDPTEu lwzu +#define STPTE stw +#define CMPPTE cmpw +#define PTE_H 0x40 +#define PTE_V 0x80000000 +#define TST_V(r) rlwinm. r,r,0,0,0 +#define SET_V(r) oris r,r,PTE_V@h +#define CLR_V(r,t) rlwinm r,r,0,1,31 + +#else +/* defines for the PTE format for 64-bit PPCs */ +#define PTE_SIZE 16 +#define PTEG_SIZE 128 +#define LG_PTEG_SIZE 7 +#define LDPTEu ldu +#define STPTE std +#define CMPPTE cmpd +#define PTE_H 2 +#define PTE_V 1 +#define TST_V(r) andi. r,r,PTE_V +#define SET_V(r) ori r,r,PTE_V +#define CLR_V(r,t) li t,PTE_V; andc r,r,t +#endif /* CONFIG_PPC64BRIDGE */ + +#define HASH_LEFT 31-(LG_PTEG_SIZE+Hash_bits-1) +#define HASH_RIGHT 31-LG_PTEG_SIZE + +_GLOBAL(create_hpte) + /* Convert linux-style PTE (r5) to low word of PPC-style PTE (r8) */ + rlwinm r8,r5,32-10,31,31 /* _PAGE_RW -> PP lsb */ + rlwinm r0,r5,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */ + and r8,r8,r0 /* writable if _RW & _DIRTY */ + rlwimi r5,r5,32-1,30,30 /* _PAGE_USER -> PP msb */ + rlwimi r5,r5,32-2,31,31 /* _PAGE_USER -> PP lsb */ + ori r8,r8,0xe14 /* clear out reserved bits and M */ + andc r8,r5,r8 /* PP = user? (rw&dirty? 2: 3): 0 */ +#ifdef CONFIG_SMP + ori r8,r8,_PAGE_COHERENT /* set M (coherence required) */ +#endif + +#ifdef CONFIG_POWER4 + /* + * XXX hack hack hack - translate 32-bit "physical" addresses + * in the linux page tables to 42-bit real addresses in such + * a fashion that we can get at the I/O we need to access. + * -- paulus + */ + cmpwi r8,0 + rlwinm r0,r8,16,16,30 + bge 57f + cmplwi r0,0xfe00 + li r0,0x3fd + bne 56f + li r0,0x3ff +56: sldi r0,r0,32 + or r8,r8,r0 +57: +#endif + + /* Construct the high word of the PPC-style PTE (r5) */ +#ifndef CONFIG_PPC64BRIDGE + rlwinm r5,r3,7,1,24 /* put VSID in 0x7fffff80 bits */ + rlwimi r5,r4,10,26,31 /* put in API (abbrev page index) */ +#else /* CONFIG_PPC64BRIDGE */ + clrlwi r3,r3,8 /* reduce vsid to 24 bits */ + sldi r5,r3,12 /* shift vsid into position */ + rlwimi r5,r4,16,20,24 /* put in API (abbrev page index) */ +#endif /* CONFIG_PPC64BRIDGE */ + SET_V(r5) /* set V (valid) bit */ + + /* Get the address of the primary PTE group in the hash table (r3) */ + .globl hash_page_patch_A +hash_page_patch_A: + addis r0,r7,Hash_base@h /* base address of hash table */ + rlwimi r0,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* VSID -> hash */ + rlwinm r3,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */ + xor r3,r3,r0 /* make primary hash */ + li r0,8 /* PTEs/group */ + + /* + * Test the _PAGE_HASHPTE bit in the old linux PTE, and skip the search + * if it is clear, meaning that the HPTE isn't there already... + */ + andi. r6,r6,_PAGE_HASHPTE + beq+ 10f /* no PTE: go look for an empty slot */ + tlbie r4 + + addis r4,r7,htab_hash_searches@ha + lwz r6,htab_hash_searches@l(r4) + addi r6,r6,1 /* count how many searches we do */ + stw r6,htab_hash_searches@l(r4) + + /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */ + mtctr r0 + addi r4,r3,-PTE_SIZE +1: LDPTEu r6,PTE_SIZE(r4) /* get next PTE */ + CMPPTE 0,r6,r5 + bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ + beq+ found_slot + + /* Search the secondary PTEG for a matching PTE */ + ori r5,r5,PTE_H /* set H (secondary hash) bit */ + .globl hash_page_patch_B +hash_page_patch_B: + xoris r4,r3,Hash_msk>>16 /* compute secondary hash */ + xori r4,r4,(-PTEG_SIZE & 0xffff) + addi r4,r4,-PTE_SIZE + mtctr r0 +2: LDPTEu r6,PTE_SIZE(r4) + CMPPTE 0,r6,r5 + bdnzf 2,2b + beq+ found_slot + xori r5,r5,PTE_H /* clear H bit again */ + + /* Search the primary PTEG for an empty slot */ +10: mtctr r0 + addi r4,r3,-PTE_SIZE /* search primary PTEG */ +1: LDPTEu r6,PTE_SIZE(r4) /* get next PTE */ + TST_V(r6) /* test valid bit */ + bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ + beq+ found_empty + + /* update counter of times that the primary PTEG is full */ + addis r4,r7,primary_pteg_full@ha + lwz r6,primary_pteg_full@l(r4) + addi r6,r6,1 + stw r6,primary_pteg_full@l(r4) + + /* Search the secondary PTEG for an empty slot */ + ori r5,r5,PTE_H /* set H (secondary hash) bit */ + .globl hash_page_patch_C +hash_page_patch_C: + xoris r4,r3,Hash_msk>>16 /* compute secondary hash */ + xori r4,r4,(-PTEG_SIZE & 0xffff) + addi r4,r4,-PTE_SIZE + mtctr r0 +2: LDPTEu r6,PTE_SIZE(r4) + TST_V(r6) + bdnzf 2,2b + beq+ found_empty + xori r5,r5,PTE_H /* clear H bit again */ + + /* + * Choose an arbitrary slot in the primary PTEG to overwrite. + * Since both the primary and secondary PTEGs are full, and we + * have no information that the PTEs in the primary PTEG are + * more important or useful than those in the secondary PTEG, + * and we know there is a definite (although small) speed + * advantage to putting the PTE in the primary PTEG, we always + * put the PTE in the primary PTEG. + */ + addis r4,r7,next_slot@ha + lwz r6,next_slot@l(r4) + addi r6,r6,PTE_SIZE + andi. r6,r6,7*PTE_SIZE +#ifdef CONFIG_POWER4 + /* + * Since we don't have BATs on POWER4, we rely on always having + * PTEs in the hash table to map the hash table and the code + * that manipulates it in virtual mode, namely flush_hash_page and + * flush_hash_segments. Otherwise we can get a DSI inside those + * routines which leads to a deadlock on the hash_table_lock on + * SMP machines. We avoid this by never overwriting the first + * PTE of each PTEG if it is already valid. + * -- paulus. + */ + bne 102f + li r6,PTE_SIZE +102: +#endif /* CONFIG_POWER4 */ + stw r6,next_slot@l(r4) + add r4,r3,r6 + + /* update counter of evicted pages */ + addis r6,r7,htab_evicts@ha + lwz r3,htab_evicts@l(r6) + addi r3,r3,1 + stw r3,htab_evicts@l(r6) + +#ifndef CONFIG_SMP + /* Store PTE in PTEG */ +found_empty: + STPTE r5,0(r4) +found_slot: + STPTE r8,PTE_SIZE/2(r4) + +#else /* CONFIG_SMP */ +/* + * Between the tlbie above and updating the hash table entry below, + * another CPU could read the hash table entry and put it in its TLB. + * There are 3 cases: + * 1. using an empty slot + * 2. updating an earlier entry to change permissions (i.e. enable write) + * 3. taking over the PTE for an unrelated address + * + * In each case it doesn't really matter if the other CPUs have the old + * PTE in their TLB. So we don't need to bother with another tlbie here, + * which is convenient as we've overwritten the register that had the + * address. :-) The tlbie above is mainly to make sure that this CPU comes + * and gets the new PTE from the hash table. + * + * We do however have to make sure that the PTE is never in an invalid + * state with the V bit set. + */ +found_empty: +found_slot: + CLR_V(r5,r0) /* clear V (valid) bit in PTE */ + STPTE r5,0(r4) + sync + TLBSYNC + STPTE r8,PTE_SIZE/2(r4) /* put in correct RPN, WIMG, PP bits */ + sync + SET_V(r5) + STPTE r5,0(r4) /* finally set V bit in PTE */ +#endif /* CONFIG_SMP */ + + sync /* make sure pte updates get to memory */ + blr + + .comm next_slot,4 + .comm primary_pteg_full,4 + .comm htab_hash_searches,4 + +/* + * Flush the entry for a particular page from the hash table. + * + * flush_hash_page(unsigned context, unsigned long va, pte_t *ptep) + * + * We assume that there is a hash table in use (Hash != 0). + */ +_GLOBAL(flush_hash_page) + /* Convert context and va to VSID */ + mulli r3,r3,897*16 /* multiply context by context skew */ + rlwinm r0,r4,4,28,31 /* get ESID (top 4 bits of va) */ + mulli r0,r0,0x111 /* multiply by ESID skew */ + add r3,r3,r0 /* note code below trims to 24 bits */ + + /* + * We disable interrupts here, even on UP, because we want + * the _PAGE_HASHPTE bit to be a reliable indication of + * whether the HPTE exists. -- paulus + */ + mfmsr r10 + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + SYNC + mtmsr r0 + SYNC + +#ifdef CONFIG_SMP + lis r9,hash_table_lock@h + ori r9,r9,hash_table_lock@l + lwz r8,PROCESSOR(r2) + oris r8,r8,9 +10: lwarx r7,0,r9 + cmpi 0,r7,0 + bne- 11f + stwcx. r8,0,r9 + beq+ 12f +11: lwz r7,0(r9) + cmpi 0,r7,0 + beq 10b + b 11b +12: isync +#endif + + /* + * Check the _PAGE_HASHPTE bit in the linux PTE. If it is + * already clear, we're done. If not, clear it (atomically) + * and proceed. -- paulus. + */ +1: lwarx r6,0,r5 /* fetch the pte */ + andi. r0,r6,_PAGE_HASHPTE + beq 9f /* done if HASHPTE is already clear */ + rlwinm r6,r6,0,31,29 /* clear HASHPTE bit */ + stwcx. r6,0,r5 /* update the pte */ + bne- 1b + + /* Construct the high word of the PPC-style PTE (r5) */ +#ifndef CONFIG_PPC64BRIDGE + rlwinm r5,r3,7,1,24 /* put VSID in 0x7fffff80 bits */ + rlwimi r5,r4,10,26,31 /* put in API (abbrev page index) */ +#else /* CONFIG_PPC64BRIDGE */ + clrlwi r3,r3,8 /* reduce vsid to 24 bits */ + sldi r5,r3,12 /* shift vsid into position */ + rlwimi r5,r4,16,20,24 /* put in API (abbrev page index) */ +#endif /* CONFIG_PPC64BRIDGE */ + SET_V(r5) /* set V (valid) bit */ + + /* Get the address of the primary PTE group in the hash table (r3) */ + .globl flush_hash_patch_A +flush_hash_patch_A: + lis r8,Hash_base@h /* base address of hash table */ + rlwimi r8,r3,LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* VSID -> hash */ + rlwinm r3,r4,20+LG_PTEG_SIZE,HASH_LEFT,HASH_RIGHT /* PI -> hash */ + xor r3,r3,r8 /* make primary hash */ + li r8,8 /* PTEs/group */ + + /* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */ + mtctr r8 + addi r7,r3,-PTE_SIZE +1: LDPTEu r0,PTE_SIZE(r7) /* get next PTE */ + CMPPTE 0,r0,r5 + bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ + beq+ 3f + + /* Search the secondary PTEG for a matching PTE */ + ori r5,r5,PTE_H /* set H (secondary hash) bit */ + .globl flush_hash_patch_B +flush_hash_patch_B: + xoris r7,r3,Hash_msk>>16 /* compute secondary hash */ + xori r7,r7,(-PTEG_SIZE & 0xffff) + addi r7,r7,-PTE_SIZE + mtctr r8 +2: LDPTEu r0,PTE_SIZE(r7) + CMPPTE 0,r0,r5 + bdnzf 2,2b + bne- 4f /* should never fail to find it */ + +3: li r0,0 + STPTE r0,0(r7) /* invalidate entry */ +4: sync + tlbie r4 /* in hw tlb too */ + sync + +#ifdef CONFIG_SMP + TLBSYNC +9: li r0,0 + stw r0,0(r9) /* clear hash_table_lock */ +#endif + +9: mtmsr r10 + SYNC + blr diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index b479a50a4588..abcc55d3cbbf 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.init.c 1.22 05/17/01 18:14:23 cort + * BK Id: SCCS/s.init.c 1.27 06/28/01 15:50:17 paulus */ /* * PowerPC version @@ -73,9 +73,15 @@ #define PGTOKB(pages) (((pages) * PAGE_SIZE) >> 10) +mm_context_t next_mmu_context; +unsigned long context_map[(LAST_CONTEXT+1) / (8*sizeof(unsigned long))]; +#ifdef FEW_CONTEXTS +atomic_t nr_free_contexts; +struct mm_struct *context_mm[LAST_CONTEXT+1]; +void steal_context(void); +#endif /* FEW_CONTEXTS */ + int prom_trashed; -atomic_t next_mmu_context; -rwlock_t context_overflow_lock __cacheline_aligned = RW_LOCK_UNLOCKED; unsigned long *end_of_DRAM; unsigned long total_memory; unsigned long total_lowmem; @@ -187,12 +193,6 @@ unsigned long __max_memory; /* max amount of low RAM to map in */ unsigned long __max_low_memory = MAX_LOW_MEM; -void __bad_pte(pmd_t *pmd) -{ - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE; -} - int do_check_pgt_cache(int low, int high) { int freed = 0; @@ -211,35 +211,6 @@ int do_check_pgt_cache(int low, int high) return freed; } -/* - * BAD_PAGE is the page that is used for page faults when linux - * is out-of-memory. Older versions of linux just did a - * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode - * unused etc.. - * - * BAD_PAGETABLE is the accompanying page-table: it is initialized - * to point to BAD_PAGE entries. - * - * ZERO_PAGE is a special page that is used for zero-initialized - * data and COW. - */ -pte_t *empty_bad_page_table; - -pte_t * __bad_pagetable(void) -{ - clear_page(empty_bad_page_table); - return empty_bad_page_table; -} - -void *empty_bad_page; - -pte_t __bad_page(void) -{ - clear_page(empty_bad_page); - return pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED)); -} - void show_mem(void) { int i,free = 0,total = 0,reserved = 0; @@ -319,21 +290,10 @@ void show_mem(void) void si_meminfo(struct sysinfo *val) { - int i; - - i = max_mapnr; - val->totalram = 0; + val->totalram = totalram_pages; val->sharedram = 0; val->freeram = nr_free_pages(); val->bufferram = atomic_read(&buffermem_pages); - while (i-- > 0) { - if (PageReserved(mem_map+i)) - continue; - val->totalram++; - if (!atomic_read(&mem_map[i].count)) - continue; - val->sharedram += atomic_read(&mem_map[i].count) - 1; - } val->totalhigh = totalhigh_pages; val->freehigh = nr_free_highpages(); val->mem_unit = PAGE_SIZE; @@ -482,14 +442,16 @@ map_page(unsigned long va, unsigned long pa, int flags) if (pg != 0) { err = 0; set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags))); - if (mem_init_done) - flush_hash_page(0, va); +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) + if (mem_init_done && Hash != 0) + flush_hash_page(0, va, pg); +#endif /* !4xx && !8xx */ } spin_unlock(&init_mm.page_table_lock); return err; } -#ifndef CONFIG_8xx +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) /* * TLB flushing: * @@ -510,19 +472,14 @@ map_page(unsigned long va, unsigned long pa, int flags) void local_flush_tlb_all(void) { -#ifdef CONFIG_PPC64BRIDGE - /* XXX this assumes that the vmalloc arena starts no lower than - * 0xd0000000 on 64-bit machines. */ - flush_hash_segments(0xd, 0xffffff); -#else - /* this could cause problems on SMP with nobats -- paulus */ - /* XXX no hash_table_lock? interesting -- paulus */ - __clear_user(Hash, Hash_size); - _tlbia(); + /* aargh!!! */ + /* just flush the kernel part of the address space, that's + all that the current callers of this require. -- paulus. */ + local_flush_tlb_range(&init_mm, TASK_SIZE, ~0UL); + #ifdef CONFIG_SMP smp_send_tlb_invalidate(0); #endif /* CONFIG_SMP */ -#endif /* CONFIG_PPC64BRIDGE */ } /* @@ -533,30 +490,18 @@ local_flush_tlb_all(void) void local_flush_tlb_mm(struct mm_struct *mm) { - if (mm->context == 0) { - /* don't try to reassign a new context to the kernel */ - /* - * This could cause problems on SMP if we aren't using - * the BATs (e.g. on POWER4 or if the nobats option is used). - * The problem scenario is that one cpu is doing - * flush_hash_page or similar when another cpu clears - * out the HPTEs which map the flush_hash_page text - * and the hash table. hash_page will then deadlock. - * We need some way to have "protected" HPTEs or else - * do all hash-table manipulation with the MMU off. - * -- paulus. - */ -#ifdef CONFIG_PPC64BRIDGE - flush_hash_segments(0xd, 0xf); -#else - flush_hash_segments(0xc, 0xf); -#endif CONFIG_PPC64BRIDGE + if (Hash == 0) { _tlbia(); return; } - mm->context = NO_CONTEXT; - if (mm == current->mm) - activate_mm(mm, mm); + + if (mm->map_count) { + struct vm_area_struct *mp; + for (mp = mm->mmap; mp != NULL; mp = mp->vm_next) + local_flush_tlb_range(mm, mp->vm_start, mp->vm_end); + } else + local_flush_tlb_range(mm, 0, TASK_SIZE); + #ifdef CONFIG_SMP smp_send_tlb_invalidate(0); #endif @@ -565,10 +510,21 @@ local_flush_tlb_mm(struct mm_struct *mm) void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) { - if (vmaddr < TASK_SIZE) - flush_hash_page(vma->vm_mm->context, vmaddr); - else - flush_hash_page(0, vmaddr); + struct mm_struct *mm; + pmd_t *pmd; + pte_t *pte; + + if (Hash == 0) { + _tlbie(vmaddr); + return; + } + mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm; + pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr); + if (!pmd_none(*pmd)) { + pte = pte_offset(pmd, vmaddr); + if (pte_val(*pte) & _PAGE_HASHPTE) + flush_hash_page(mm->context, vmaddr, pte); + } #ifdef CONFIG_SMP smp_send_tlb_invalidate(0); #endif @@ -576,28 +532,43 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) /* - * for each page addr in the range, call MMU_invalidate_page() - * if the range is very large and the hash table is small it might be - * faster to do a search of the hash table and just invalidate pages - * that are in the range but that's for study later. - * -- Cort + * For each address in the range, find the pte for the address + * and check _PAGE_HASHPTE bit; if it is set, find and destroy + * the corresponding HPTE. */ void local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - start &= PAGE_MASK; + pmd_t *pmd; + pte_t *pte; + unsigned long pmd_end; + unsigned int ctx = mm->context; - if (mm->context != 0) { - if (end > TASK_SIZE) - end = TASK_SIZE; - if (end - start > 20 * PAGE_SIZE) { - flush_tlb_mm(mm); - return; - } + if (Hash == 0) { + _tlbia(); + return; } - - for (; start < end; start += PAGE_SIZE) - flush_hash_page(mm->context, start); + start &= PAGE_MASK; + if (start >= end) + return; + pmd = pmd_offset(pgd_offset(mm, start), start); + do { + pmd_end = (start + PGDIR_SIZE) & PGDIR_MASK; + if (!pmd_none(*pmd)) { + if (!pmd_end || pmd_end > end) + pmd_end = end; + pte = pte_offset(pmd, start); + do { + if ((pte_val(*pte) & _PAGE_HASHPTE) != 0) + flush_hash_page(ctx, start, pte); + start += PAGE_SIZE; + ++pte; + } while (start && start < pmd_end); + } else { + start = pmd_end; + } + ++pmd; + } while (start && start < end); #ifdef CONFIG_SMP smp_send_tlb_invalidate(0); @@ -605,59 +576,6 @@ local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long e } /* - * The context counter has overflowed. - * We set mm->context to NO_CONTEXT for all mm's in the system. - * We assume we can get to all mm's by looking as tsk->mm for - * all tasks in the system. - */ -void -mmu_context_overflow(void) -{ - struct task_struct *tsk; - - printk(KERN_DEBUG "mmu_context_overflow\n"); - /* acquire the write lock for context overflow */ - write_lock (&context_overflow_lock); - /* recheck if overflow still exists */ - if (atomic_read(&next_mmu_context) == LAST_CONTEXT) { - read_lock(&tasklist_lock); - for_each_task(tsk) { - if (tsk->mm) - tsk->mm->context = NO_CONTEXT; - } - read_unlock(&tasklist_lock); - flush_hash_segments(0x10, 0xffffff); -#ifdef CONFIG_SMP - smp_send_tlb_invalidate(0); -#endif - atomic_set(&next_mmu_context, 0); - } - write_unlock (&context_overflow_lock); - /* make sure current always has a context */ - /* need to check to assure current task has an mm */ - /* - idle thread does not have an MM */ - if (current->mm) { - current->mm->context = MUNGE_CONTEXT(atomic_inc_return(&next_mmu_context)); - set_context(current->mm->context, current->mm->pgd); - } -} -#else /* CONFIG_8xx */ -void -mmu_context_overflow(void) -{ - atomic_set(&next_mmu_context, -1); -} -#endif /* CONFIG_8xx */ - -void flush_page_to_ram(struct page *page) -{ - unsigned long vaddr = (unsigned long) kmap(page); - __flush_page_to_ram(vaddr); - kunmap(page); -} - -#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -/* * Set up one of the I/D BAT (block address translation) register pairs. * The parameters are not checked; in particular size must be a power * of 2 between 128k and 256M. @@ -717,8 +635,6 @@ void __init setbat(int index, unsigned long virt, unsigned long phys, /* * Map in all of physical memory starting at KERNELBASE. */ -#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) - static void __init mapin_ram(void) { unsigned long v, p, s, f; @@ -768,10 +684,10 @@ static void __init mapin_ram(void) f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED; #if defined(CONFIG_KGDB) || defined(CONFIG_XMON) /* Allows stub to set breakpoints everywhere */ - f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE; + f |= _PAGE_RW | _PAGE_DIRTY; #else if ((char *) v < _stext || (char *) v >= etext) - f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE; + f |= _PAGE_RW | _PAGE_DIRTY; #ifndef CONFIG_8xx else /* On the powerpc (not 8xx), no user access @@ -839,16 +755,59 @@ void free_initmem(void) #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); + for (; start < end; start += PAGE_SIZE) { ClearPageReserved(virt_to_page(start)); set_page_count(virt_to_page(start), 1); free_page(start); totalram_pages++; } - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); } #endif +/* + * Initialize the context management stuff. + */ +static void mmu_context_init(void) +{ + context_map[0] = 1; /* init_mm uses context 0 */ + next_mmu_context = 1; +#ifdef FEW_CONTEXTS + atomic_set(&nr_free_contexts, LAST_CONTEXT); + context_mm[0] = &init_mm; +#endif /* FEW_CONTEXTS */ +} + +#ifdef FEW_CONTEXTS +/* + * Steal a context from a task that has one at the moment. + * This is only used on 8xx and 4xx and we presently assume that + * they don't do SMP. If they do then this will have to check + * whether the MM we steal is in use. + * We also assume that this is only used on systems that don't + * use an MMU hash table - this is true for 8xx and 4xx. + * This isn't an LRU system, it just frees up each context in + * turn (sort-of pseudo-random replacement :). This would be the + * place to implement an LRU scheme if anyone was motivated to do it. + * -- paulus + */ +void steal_context(void) +{ + struct mm_struct *mm; + + /* free up context `next_mmu_context' */ + /* if we shouldn't free context 0, don't... */ +#ifdef CONFIG_4xx + if (next_mmu_context == 0) + next_mmu_context = 1; +#endif /* CONFIG_4xx */ + mm = context_mm[next_mmu_context]; + flush_tlb_mm(mm); + destroy_context(mm); +} +#endif /* FEW_CONTEXTS */ + extern boot_infos_t *disp_bi; /* @@ -903,6 +862,8 @@ MMU_init(void) mtspr(SPRN_DCCR, 0x80000000); /* 128 MB of data space at 0x0. */ mtspr(SPRN_ICCR, 0x80000000); /* 128 MB of instr. space at 0x0. */ + + mmu_context_init(); } #else /* !CONFIG_4xx */ @@ -938,11 +899,7 @@ void __init MMU_init(void) /* Map in all of RAM starting at KERNELBASE */ mapin_ram(); -#if defined(CONFIG_POWER4) - ioremap_base = ioremap_bot = 0xfffff000; - isa_io_base = (unsigned long) ioremap(0xffd00000, 0x200000) + 0x100000; - -#elif defined(CONFIG_8xx) +#if defined(CONFIG_8xx) /* Now map in some of the I/O space that is generically needed * or shared with multiple devices. * All of this fits into the same 4Mbyte region, so it only @@ -974,7 +931,7 @@ void __init MMU_init(void) #ifdef CONFIG_PCI ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE); #endif -#else /* !CONFIG_POWER4 && !CONFIG_8xx */ +#else /* !CONFIG_8xx */ /* * Setup the bat mappings we're going to load that cover * the io areas. RAM was mapped by mapin_ram(). @@ -1024,7 +981,7 @@ void __init MMU_init(void) break; } ioremap_bot = ioremap_base; -#endif /* CONFIG_POWER4 || CONFIG_8xx */ +#endif /* CONFIG_8xx */ if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211); #ifdef CONFIG_BOOTX_TEXT @@ -1032,6 +989,8 @@ void __init MMU_init(void) if (_machine == _MACH_Pmac || _machine == _MACH_chrp) map_bootx_text(); #endif + + mmu_context_init(); } #endif /* CONFIG_4xx */ @@ -1095,12 +1054,6 @@ void __init paging_init(void) #endif /* CONFIG_HIGHMEM */ /* - * Grab some memory for bad_page and bad_pagetable to use. - */ - empty_bad_page = alloc_bootmem_pages(PAGE_SIZE); - empty_bad_page_table = alloc_bootmem_pages(PAGE_SIZE); - - /* * All pages are DMA-able so we put them all in the DMA zone. */ zones_size[ZONE_DMA] = total_lowmem >> PAGE_SHIFT; @@ -1128,7 +1081,6 @@ void __init mem_init(void) highmem_mapnr = total_lowmem >> PAGE_SHIFT; highmem_start_page = mem_map + highmem_mapnr; max_mapnr = total_memory >> PAGE_SHIFT; - totalram_pages += max_mapnr - highmem_mapnr; #else max_mapnr = max_low_pfn; #endif /* CONFIG_HIGHMEM */ @@ -1201,15 +1153,17 @@ void __init mem_init(void) #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) /* - * Initialize the hash table and patch the instructions in head.S. + * Initialize the hash table and patch the instructions in hashtable.S. */ static void __init hash_init(void) { int Hash_bits, mb, mb2; unsigned int hmask, h; - extern unsigned int hash_page_patch_A[], hash_page_patch_B[], - hash_page_patch_C[], hash_page[]; + extern unsigned int hash_page_patch_A[]; + extern unsigned int hash_page_patch_B[], hash_page_patch_C[]; + extern unsigned int hash_page[]; + extern unsigned int flush_hash_patch_A[], flush_hash_patch_B[]; #ifdef CONFIG_PPC64BRIDGE /* The hash table has already been allocated and initialized @@ -1259,6 +1213,7 @@ static void __init hash_init(void) if ( Hash_size ) { Hash = mem_pieces_find(Hash_size, Hash_size); cacheable_memzero(Hash, Hash_size); + _SDR1 = __pa(Hash) | (Hash_mask >> 10); } else Hash = 0; #endif /* CONFIG_PPC64BRIDGE */ @@ -1271,10 +1226,10 @@ static void __init hash_init(void) Hash_end = (PTE *) ((unsigned long)Hash + Hash_size); /* - * Patch up the instructions in head.S:hash_page + * Patch up the instructions in hashtable.S:create_hpte */ hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff) - | (__pa(Hash) >> 16); + | ((unsigned int)(Hash) >> 16); hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) | (mb << 6); hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0) @@ -1283,10 +1238,6 @@ static void __init hash_init(void) | hmask; hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff) | hmask; -#if 0 /* see hash_page in head.S, note also patch_C ref below */ - hash_page_patch_D[0] = (hash_page_patch_D[0] & ~0xffff) - | hmask; -#endif /* * Ensure that the locations we've patched have been written * out from the data cache and invalidated in the instruction @@ -1294,6 +1245,19 @@ static void __init hash_init(void) */ flush_icache_range((unsigned long) &hash_page_patch_A[0], (unsigned long) &hash_page_patch_C[1]); + /* + * Patch up the instructions in hashtable.S:flush_hash_page + */ + flush_hash_patch_A[0] = (flush_hash_patch_A[0] & ~0xffff) + | ((unsigned int)(Hash) >> 16); + flush_hash_patch_A[1] = (flush_hash_patch_A[1] & ~0x7c0) + | (mb << 6); + flush_hash_patch_A[2] = (flush_hash_patch_A[2] & ~0x7c0) + | (mb2 << 6); + flush_hash_patch_B[0] = (flush_hash_patch_B[0] & ~0xffff) + | hmask; + flush_icache_range((unsigned long) &flush_hash_patch_A[0], + (unsigned long) &flush_hash_patch_B[1]); } else { Hash_end = 0; @@ -1306,6 +1270,7 @@ static void __init hash_init(void) flush_icache_range((unsigned long) &hash_page[0], (unsigned long) &hash_page[1]); } + if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205); } #endif /* !CONFIG_4xx && !CONFIG_8xx */ @@ -1320,7 +1285,7 @@ set_phys_avail(unsigned long total_memory) unsigned long kstart, ksize; /* - * Initially, available phyiscal memory is equivalent to all + * Initially, available physical memory is equivalent to all * physical memory. */ @@ -1357,3 +1322,50 @@ set_phys_avail(unsigned long total_memory) mem_pieces_remove(&phys_avail, __pa(Hash), Hash_size, 1); #endif /* CONFIG_PPC64BRIDGE */ } + +void flush_page_to_ram(struct page *page) +{ + unsigned long vaddr = (unsigned long) kmap(page); + __flush_page_to_ram(vaddr); + kunmap(page); +} + +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) +/* + * This is called at the end of handling a user page fault, when the + * fault has been handled by updating a PTE in the linux page tables. + * We use it to preload an HPTE into the hash table corresponding to + * the updated linux PTE. + */ +void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, + pte_t pte) +{ + struct mm_struct *mm; + pmd_t *pmd; + pte_t *ptep; + static int nopreload; + + if (Hash == 0 || nopreload) + return; + mm = (address < TASK_SIZE)? vma->vm_mm: &init_mm; + pmd = pmd_offset(pgd_offset(mm, address), address); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, address); + add_hash_page(mm->context, address, ptep); + } +} +#endif /* !4xx && !8xx */ + +/* + * set_pte stores a linux PTE into the linux page table. + * On machines which use an MMU hash table we avoid changing the + * _PAGE_HASHPTE bit. + */ +void set_pte(pte_t *ptep, pte_t pte) +{ +#if _PAGE_HASHPTE != 0 + pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte) & ~_PAGE_HASHPTE); +#else + *ptep = pte; +#endif +} diff --git a/arch/ppc/vmlinux.lds b/arch/ppc/vmlinux.lds index 9ca864b729e1..0c5f8ca77534 100644 --- a/arch/ppc/vmlinux.lds +++ b/arch/ppc/vmlinux.lds @@ -39,6 +39,7 @@ SECTIONS .rodata : { *(.rodata) + *(.rodata.*) *(.rodata1) } .kstrtab : { *(.kstrtab) } diff --git a/arch/ppc/xmon/Makefile b/arch/ppc/xmon/Makefile index c58b551b3917..2c0ac26401d4 100644 --- a/arch/ppc/xmon/Makefile +++ b/arch/ppc/xmon/Makefile @@ -1,13 +1,14 @@ -# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:23 cort +# BK Id: SCCS/s.Makefile 1.6 06/27/01 14:49:58 trini # # Makefile for xmon O_TARGET := x.o -ifeq ($(CONFIG_8xx),y) -obj-y := start_8xx.o xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o +ifdef CONFIG_8xx +obj-y := start_8xx.o else -obj-y := start.o xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o +obj-y := start.o endif +obj-y += xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o include $(TOPDIR)/Rules.make diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c index 37f80c49c646..68a8adb45846 100644 --- a/arch/ppc/xmon/xmon.c +++ b/arch/ppc/xmon/xmon.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.xmon.c 1.12 06/09/01 22:18:05 paulus + * BK Id: SCCS/s.xmon.c 1.14 06/28/01 15:50:17 paulus */ /* * Routines providing a simple monitor for use on the PowerMac. @@ -1017,7 +1017,8 @@ dump_hash_table() seg_end = (seg << 28) | 0x0ffff000; if (seg_end > hash_end) seg_end = hash_end; - dump_hash_table_seg((hash_ctx << 4) + seg, seg_start, seg_end); + dump_hash_table_seg((hash_ctx << 4) + (seg * 0x111), + seg_start, seg_end); seg_start = seg_end + 0x1000; } } diff --git a/arch/s390/vmlinux.lds b/arch/s390/vmlinux.lds index 4d93bcc7a9a1..2bf285009f05 100644 --- a/arch/s390/vmlinux.lds +++ b/arch/s390/vmlinux.lds @@ -14,7 +14,7 @@ SECTIONS *(.gnu.warning) } = 0x0700 .text.lock : { *(.text.lock) } /* out-of-line lock text */ - .rodata : { *(.rodata) } + .rodata : { *(.rodata) *(.rodata.*) } .kstrtab : { *(.kstrtab) } . = ALIGN(16); /* Exception table */ diff --git a/arch/s390x/vmlinux.lds b/arch/s390x/vmlinux.lds index 10a9d88364c0..f8dd0265bee3 100644 --- a/arch/s390x/vmlinux.lds +++ b/arch/s390x/vmlinux.lds @@ -14,7 +14,7 @@ SECTIONS *(.gnu.warning) } = 0x0700 .text.lock : { *(.text.lock) } /* out-of-line lock text */ - .rodata : { *(.rodata) } + .rodata : { *(.rodata) *(.rodata.*) } .kstrtab : { *(.kstrtab) } . = ALIGN(16); /* Exception table */ diff --git a/arch/sh/vmlinux.lds.S b/arch/sh/vmlinux.lds.S index 5d3f8a66d1c9..ad24b196f03e 100644 --- a/arch/sh/vmlinux.lds.S +++ b/arch/sh/vmlinux.lds.S @@ -24,7 +24,7 @@ SECTIONS *(.gnu.warning) } = 0x0009 .text.lock : { *(.text.lock) } /* out-of-line lock text */ - .rodata : { *(.rodata) } + .rodata : { *(.rodata) *(.rodata.*) } .kstrtab : { *(.kstrtab) } . = ALIGN(16); /* Exception table */ diff --git a/arch/sparc/vmlinux.lds b/arch/sparc/vmlinux.lds index e449e26fa8a7..bd177538eac9 100644 --- a/arch/sparc/vmlinux.lds +++ b/arch/sparc/vmlinux.lds @@ -12,7 +12,7 @@ SECTIONS } =0 _etext = .; PROVIDE (etext = .); - .rodata : { *(.rodata) } + .rodata : { *(.rodata) *(.rodata.*) } .rodata1 : { *(.rodata1) } .data : { diff --git a/arch/sparc64/vmlinux.lds b/arch/sparc64/vmlinux.lds index 91d4575d0594..12e9c234e386 100644 --- a/arch/sparc64/vmlinux.lds +++ b/arch/sparc64/vmlinux.lds @@ -16,7 +16,7 @@ SECTIONS } =0 _etext = .; PROVIDE (etext = .); - .rodata : { *(.rodata) } + .rodata : { *(.rodata) *(.rodata.*) } .rodata1 : { *(.rodata1) } .data : { diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 391abec031b9..800debe3b416 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -63,6 +63,7 @@ const struct pci_device_id cciss_pci_device_id[] = { 0x0E11, 0x4080, 0, 0, 0}, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4082, 0, 0, 0}, + {0,} }; MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); diff --git a/drivers/char/Config.in b/drivers/char/Config.in index bd0f467f943d..9259d21124cd 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -186,6 +186,7 @@ if [ "$CONFIG_AGP" != "n" ]; then bool ' AMD Irongate support' CONFIG_AGP_AMD bool ' Generic SiS support' CONFIG_AGP_SIS bool ' ALI chipset support' CONFIG_AGP_ALI + bool ' Severworks LE/HE support' CONFIG_AGP_SWORKS fi source drivers/char/drm/Config.in diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 8e5b4bede4c6..ac94c07dcf31 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -123,11 +123,11 @@ struct agp_bridge_data { #define OUTREG32(mmap, addr, val) __raw_writel((val), (mmap)+(addr)) #define OUTREG16(mmap, addr, val) __raw_writew((val), (mmap)+(addr)) -#define OUTREG8 (mmap, addr, val) __raw_writeb((val), (mmap)+(addr)) +#define OUTREG8(mmap, addr, val) __raw_writeb((val), (mmap)+(addr)) #define INREG32(mmap, addr) __raw_readl((mmap)+(addr)) #define INREG16(mmap, addr) __raw_readw((mmap)+(addr)) -#define INREG8 (mmap, addr) __raw_readb((mmap)+(addr)) +#define INREG8(mmap, addr) __raw_readb((mmap)+(addr)) #define CACHE_FLUSH agp_bridge.cache_flush #define A_SIZE_8(x) ((aper_size_info_8 *) x) @@ -292,4 +292,23 @@ struct agp_bridge_data { #define ALI_CACHE_FLUSH_ADDR_MASK 0xFFFFF000 #define ALI_CACHE_FLUSH_EN 0x100 +/* Serverworks Registers */ +#define SVWRKS_APSIZE 0x10 +#define SVWRKS_SIZE_MASK 0xfe000000 + +#define SVWRKS_MMBASE 0x14 +#define SVWRKS_CACHING 0x4b +#define SVWRKS_FEATURE 0x68 + +/* func 1 registers */ +#define SVWRKS_AGP_ENABLE 0x60 +#define SVWRKS_COMMAND 0x04 + +/* Memory mapped registers */ +#define SVWRKS_GART_CACHE 0x02 +#define SVWRKS_GATTBASE 0x04 +#define SVWRKS_TLBFLUSH 0x10 +#define SVWRKS_POSTFLUSH 0x14 +#define SVWRKS_DIRFLUSH 0x0c + #endif /* _AGP_BACKEND_PRIV_H */ diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c index dafe4e4fc596..543ffa04918f 100644 --- a/drivers/char/agp/agpgart_be.c +++ b/drivers/char/agp/agpgart_be.c @@ -2189,6 +2189,621 @@ static int __init ali_generic_setup (struct pci_dev *pdev) #endif /* CONFIG_AGP_ALI */ +#ifdef CONFIG_AGP_SWORKS +typedef struct _serverworks_page_map { + unsigned long *real; + unsigned long *remapped; +} serverworks_page_map; + +static struct _serverworks_private { + struct pci_dev *svrwrks_dev; /* device one */ + volatile u8 *registers; + serverworks_page_map **gatt_pages; + int num_tables; + serverworks_page_map scratch_dir; + + int gart_addr_ofs; + int mm_addr_ofs; +} serverworks_private; + +static int serverworks_create_page_map(serverworks_page_map *page_map) +{ + int i; + + page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); + if (page_map->real == NULL) { + return -ENOMEM; + } + set_bit(PG_reserved, &virt_to_page(page_map->real)->flags); + CACHE_FLUSH(); + page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), + PAGE_SIZE); + if (page_map->remapped == NULL) { + clear_bit(PG_reserved, + &virt_to_page(page_map->real)->flags); + free_page((unsigned long) page_map->real); + page_map->real = NULL; + return -ENOMEM; + } + CACHE_FLUSH(); + + for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { + page_map->remapped[i] = agp_bridge.scratch_page; + } + + return 0; +} + +static void serverworks_free_page_map(serverworks_page_map *page_map) +{ + iounmap(page_map->remapped); + clear_bit(PG_reserved, + &virt_to_page(page_map->real)->flags); + free_page((unsigned long) page_map->real); +} + +static void serverworks_free_gatt_pages(void) +{ + int i; + serverworks_page_map **tables; + serverworks_page_map *entry; + + tables = serverworks_private.gatt_pages; + for(i = 0; i < serverworks_private.num_tables; i++) { + entry = tables[i]; + if (entry != NULL) { + if (entry->real != NULL) { + serverworks_free_page_map(entry); + } + kfree(entry); + } + } + kfree(tables); +} + +static int serverworks_create_gatt_pages(int nr_tables) +{ + serverworks_page_map **tables; + serverworks_page_map *entry; + int retval = 0; + int i; + + tables = kmalloc((nr_tables + 1) * sizeof(serverworks_page_map *), + GFP_KERNEL); + if (tables == NULL) { + return -ENOMEM; + } + memset(tables, 0, sizeof(serverworks_page_map *) * (nr_tables + 1)); + for (i = 0; i < nr_tables; i++) { + entry = kmalloc(sizeof(serverworks_page_map), GFP_KERNEL); + if (entry == NULL) { + retval = -ENOMEM; + break; + } + memset(entry, 0, sizeof(serverworks_page_map)); + tables[i] = entry; + retval = serverworks_create_page_map(entry); + if (retval != 0) break; + } + serverworks_private.num_tables = nr_tables; + serverworks_private.gatt_pages = tables; + + if (retval != 0) serverworks_free_gatt_pages(); + + return retval; +} + +#define SVRWRKS_GET_GATT(addr) (serverworks_private.gatt_pages[\ + GET_PAGE_DIR_IDX(addr)]->remapped) + +#ifndef GET_PAGE_DIR_OFF +#define GET_PAGE_DIR_OFF(addr) (addr >> 22) +#endif + +#ifndef GET_PAGE_DIR_IDX +#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \ + GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr)) +#endif + +#ifndef GET_GATT_OFF +#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) +#endif + +static int serverworks_create_gatt_table(void) +{ + aper_size_info_lvl2 *value; + serverworks_page_map page_dir; + int retval; + u32 temp; + int i; + + value = A_SIZE_LVL2(agp_bridge.current_size); + retval = serverworks_create_page_map(&page_dir); + if (retval != 0) { + return retval; + } + retval = serverworks_create_page_map(&serverworks_private.scratch_dir); + if (retval != 0) { + serverworks_free_page_map(&page_dir); + return retval; + } + /* Create a fake scratch directory */ + for(i = 0; i < 1024; i++) { + serverworks_private.scratch_dir.remapped[i] = (unsigned long) agp_bridge.scratch_page; + page_dir.remapped[i] = + virt_to_bus(serverworks_private.scratch_dir.real); + page_dir.remapped[i] |= 0x00000001; + } + + retval = serverworks_create_gatt_pages(value->num_entries / 1024); + if (retval != 0) { + serverworks_free_page_map(&page_dir); + return retval; + } + + agp_bridge.gatt_table_real = page_dir.real; + agp_bridge.gatt_table = page_dir.remapped; + agp_bridge.gatt_bus_addr = virt_to_bus(page_dir.real); + + /* Get the address for the gart region. + * This is a bus address even on the alpha, b/c its + * used to program the agp master not the cpu + */ + + pci_read_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* Calculate the agp offset */ + + for(i = 0; i < value->num_entries / 1024; i++) { + page_dir.remapped[i] = + virt_to_bus(serverworks_private.gatt_pages[i]->real); + page_dir.remapped[i] |= 0x00000001; + } + + return 0; +} + +static int serverworks_free_gatt_table(void) +{ + serverworks_page_map page_dir; + + page_dir.real = agp_bridge.gatt_table_real; + page_dir.remapped = agp_bridge.gatt_table; + + serverworks_free_gatt_pages(); + serverworks_free_page_map(&page_dir); + return 0; +} + +static int serverworks_fetch_size(void) +{ + int i; + u32 temp; + u32 temp2; + aper_size_info_lvl2 *values; + + values = A_SIZE_LVL2(agp_bridge.aperture_sizes); + pci_read_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + &temp); + pci_write_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + 0xfe000000); + pci_read_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + &temp2); + pci_write_config_dword(agp_bridge.dev, + serverworks_private.gart_addr_ofs, + temp); + temp2 &= SVWRKS_SIZE_MASK; + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp2 == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + +static int serverworks_configure(void) +{ + aper_size_info_lvl2 *current_size; + u32 temp; + u8 enable_reg; + u8 cap_ptr; + u32 cap_id; + u16 cap_reg; + + current_size = A_SIZE_LVL2(agp_bridge.current_size); + + /* Get the memory mapped registers */ + pci_read_config_dword(agp_bridge.dev, + serverworks_private.mm_addr_ofs, + &temp); + temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); + serverworks_private.registers = (volatile u8 *) ioremap(temp, 4096); + + OUTREG8(serverworks_private.registers, SVWRKS_GART_CACHE, 0x0a); + + OUTREG32(serverworks_private.registers, SVWRKS_GATTBASE, + agp_bridge.gatt_bus_addr); + + cap_reg = INREG16(serverworks_private.registers, SVWRKS_COMMAND); + cap_reg &= ~0x0007; + cap_reg |= 0x4; + OUTREG16(serverworks_private.registers, SVWRKS_COMMAND, cap_reg); + + pci_read_config_byte(serverworks_private.svrwrks_dev, + SVWRKS_AGP_ENABLE, &enable_reg); + enable_reg |= 0x1; /* Agp Enable bit */ + pci_write_config_byte(serverworks_private.svrwrks_dev, + SVWRKS_AGP_ENABLE, enable_reg); + agp_bridge.tlb_flush(NULL); + + pci_read_config_byte(serverworks_private.svrwrks_dev, 0x34, &cap_ptr); + if (cap_ptr != 0x00) { + do { + pci_read_config_dword(serverworks_private.svrwrks_dev, + cap_ptr, &cap_id); + + if ((cap_id & 0xff) != 0x02) + cap_ptr = (cap_id >> 8) & 0xff; + } + while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); + } + agp_bridge.capndx = cap_ptr; + + /* Fill in the mode register */ + pci_read_config_dword(serverworks_private.svrwrks_dev, + agp_bridge.capndx + 4, + &agp_bridge.mode); + + pci_read_config_byte(agp_bridge.dev, + SVWRKS_CACHING, + &enable_reg); + enable_reg &= ~0x3; + pci_write_config_byte(agp_bridge.dev, + SVWRKS_CACHING, + enable_reg); + + pci_read_config_byte(agp_bridge.dev, + SVWRKS_FEATURE, + &enable_reg); + enable_reg |= (1<<6); + pci_write_config_byte(agp_bridge.dev, + SVWRKS_FEATURE, + enable_reg); + + return 0; +} + +static void serverworks_cleanup(void) +{ + iounmap((void *) serverworks_private.registers); +} + +/* + * This routine could be implemented by taking the addresses + * written to the GATT, and flushing them individually. However + * currently it just flushes the whole table. Which is probably + * more efficent, since agp_memory blocks can be a large number of + * entries. + */ + +static void serverworks_tlbflush(agp_memory * temp) +{ + unsigned long end; + + OUTREG8(serverworks_private.registers, SVWRKS_POSTFLUSH, 0x01); + end = jiffies + 3*HZ; + while(INREG8(serverworks_private.registers, + SVWRKS_POSTFLUSH) == 0x01) { + if((signed)(end - jiffies) <= 0) { + printk(KERN_ERR "Posted write buffer flush took more" + "then 3 seconds\n"); + } + } + OUTREG32(serverworks_private.registers, SVWRKS_DIRFLUSH, 0x00000001); + end = jiffies + 3*HZ; + while(INREG32(serverworks_private.registers, + SVWRKS_DIRFLUSH) == 0x00000001) { + if((signed)(end - jiffies) <= 0) { + printk(KERN_ERR "TLB flush took more" + "then 3 seconds\n"); + } + } +} + +static unsigned long serverworks_mask_memory(unsigned long addr, int type) +{ + /* Only type 0 is supported by the serverworks chipsets */ + + return addr | agp_bridge.masks[0].mask; +} + +static int serverworks_insert_memory(agp_memory * mem, + off_t pg_start, int type) +{ + int i, j, num_entries; + unsigned long *cur_gatt; + unsigned long addr; + + num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + if ((pg_start + mem->page_count) > num_entries) { + return -EINVAL; + } + + j = pg_start; + while (j < (pg_start + mem->page_count)) { + addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = SVRWRKS_GET_GATT(addr); + if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) { + return -EBUSY; + } + j++; + } + + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } + + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = SVRWRKS_GET_GATT(addr); + cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; + } + agp_bridge.tlb_flush(mem); + return 0; +} + +static int serverworks_remove_memory(agp_memory * mem, off_t pg_start, + int type) +{ + int i; + unsigned long *cur_gatt; + unsigned long addr; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + + CACHE_FLUSH(); + agp_bridge.tlb_flush(mem); + + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = SVRWRKS_GET_GATT(addr); + cur_gatt[GET_GATT_OFF(addr)] = + (unsigned long) agp_bridge.scratch_page; + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static gatt_mask serverworks_masks[] = +{ + {0x00000001, 0} +}; + +static aper_size_info_lvl2 serverworks_sizes[7] = +{ + {2048, 524288, 0x80000000}, + {1024, 262144, 0xc0000000}, + {512, 131072, 0xe0000000}, + {256, 65536, 0xf0000000}, + {128, 32768, 0xf8000000}, + {64, 16384, 0xfc000000}, + {32, 8192, 0xfe000000} +}; + +static void serverworks_agp_enable(u32 mode) +{ + struct pci_dev *device = NULL; + u32 command, scratch, cap_id; + u8 cap_ptr; + + pci_read_config_dword(serverworks_private.svrwrks_dev, + agp_bridge.capndx + 4, + &command); + + /* + * PASS1: go throu all devices that claim to be + * AGP devices and collect their data. + */ + + while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, + device)) != NULL) { + pci_read_config_dword(device, 0x04, &scratch); + + if (!(scratch & 0x00100000)) + continue; + + pci_read_config_byte(device, 0x34, &cap_ptr); + + if (cap_ptr != 0x00) { + do { + pci_read_config_dword(device, + cap_ptr, &cap_id); + + if ((cap_id & 0xff) != 0x02) + cap_ptr = (cap_id >> 8) & 0xff; + } + while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); + } + if (cap_ptr != 0x00) { + /* + * Ok, here we have a AGP device. Disable impossible + * settings, and adjust the readqueue to the minimum. + */ + + pci_read_config_dword(device, cap_ptr + 4, &scratch); + + /* adjust RQ depth */ + command = + ((command & ~0xff000000) | + min((mode & 0xff000000), + min((command & 0xff000000), + (scratch & 0xff000000)))); + + /* disable SBA if it's not supported */ + if (!((command & 0x00000200) && + (scratch & 0x00000200) && + (mode & 0x00000200))) + command &= ~0x00000200; + + /* disable FW */ + command &= ~0x00000010; + + command &= ~0x00000008; + + if (!((command & 4) && + (scratch & 4) && + (mode & 4))) + command &= ~0x00000004; + + if (!((command & 2) && + (scratch & 2) && + (mode & 2))) + command &= ~0x00000002; + + if (!((command & 1) && + (scratch & 1) && + (mode & 1))) + command &= ~0x00000001; + } + } + /* + * PASS2: Figure out the 4X/2X/1X setting and enable the + * target (our motherboard chipset). + */ + + if (command & 4) { + command &= ~3; /* 4X */ + } + if (command & 2) { + command &= ~5; /* 2X */ + } + if (command & 1) { + command &= ~6; /* 1X */ + } + command |= 0x00000100; + + pci_write_config_dword(serverworks_private.svrwrks_dev, + agp_bridge.capndx + 8, + command); + + /* + * PASS3: Go throu all AGP devices and update the + * command registers. + */ + + while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, + device)) != NULL) { + pci_read_config_dword(device, 0x04, &scratch); + + if (!(scratch & 0x00100000)) + continue; + + pci_read_config_byte(device, 0x34, &cap_ptr); + + if (cap_ptr != 0x00) { + do { + pci_read_config_dword(device, + cap_ptr, &cap_id); + + if ((cap_id & 0xff) != 0x02) + cap_ptr = (cap_id >> 8) & 0xff; + } + while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); + } + if (cap_ptr != 0x00) + pci_write_config_dword(device, cap_ptr + 8, command); + } +} + +static int __init serverworks_setup (struct pci_dev *pdev) +{ + u32 temp; + u32 temp2; + + serverworks_private.svrwrks_dev = pdev; + + agp_bridge.masks = serverworks_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) serverworks_sizes; + agp_bridge.size_type = LVL2_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = (void *) &serverworks_private; + agp_bridge.needs_scratch_page = TRUE; + agp_bridge.configure = serverworks_configure; + agp_bridge.fetch_size = serverworks_fetch_size; + agp_bridge.cleanup = serverworks_cleanup; + agp_bridge.tlb_flush = serverworks_tlbflush; + agp_bridge.mask_memory = serverworks_mask_memory; + agp_bridge.agp_enable = serverworks_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = serverworks_create_gatt_table; + agp_bridge.free_gatt_table = serverworks_free_gatt_table; + agp_bridge.insert_memory = serverworks_insert_memory; + agp_bridge.remove_memory = serverworks_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + agp_bridge.agp_alloc_page = agp_generic_alloc_page; + agp_bridge.agp_destroy_page = agp_generic_destroy_page; + + pci_read_config_dword(agp_bridge.dev, + SVWRKS_APSIZE, + &temp); + + serverworks_private.gart_addr_ofs = 0x10; + + if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { + pci_read_config_dword(agp_bridge.dev, + SVWRKS_APSIZE + 4, + &temp2); + if(temp2 != 0) { + printk("Detected 64 bit aperture address, but top " + "bits are not zero. Disabling agp\n"); + return -ENODEV; + } + serverworks_private.mm_addr_ofs = 0x18; + } else { + serverworks_private.mm_addr_ofs = 0x14; + } + + pci_read_config_dword(agp_bridge.dev, + serverworks_private.mm_addr_ofs, + &temp); + if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { + pci_read_config_dword(agp_bridge.dev, + serverworks_private.mm_addr_ofs + 4, + &temp2); + if(temp2 != 0) { + printk("Detected 64 bit MMIO address, but top " + "bits are not zero. Disabling agp\n"); + return -ENODEV; + } + } + + return 0; +} + +#endif /* CONFIG_AGP_SWORKS */ + /* per-chipset initialization data. * note -- all chipsets for a single vendor MUST be grouped together @@ -2586,6 +3201,41 @@ static int __init agp_find_supported_device(void) } #endif /* CONFIG_AGP_I810 */ +#ifdef CONFIG_AGP_SWORKS + /* Everything is on func 1 here so we are hardcoding function one */ + if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS) { + struct pci_dev *bridge_dev; + + bridge_dev = pci_find_slot ((unsigned int)dev->bus->number, + PCI_DEVFN(0, 1)); + if(bridge_dev == NULL) { + printk(KERN_INFO PFX "agpgart: Detected a Serverworks " + "Chipset, but could not find the secondary " + "device.\n"); + return -ENODEV; + } + + switch (dev->device) { + case PCI_DEVICE_ID_SERVERWORKS_HE: + agp_bridge.type = SVWRKS_HE; + return serverworks_setup(bridge_dev); + + case PCI_DEVICE_ID_SERVERWORKS_LE: + case 0x0007: + agp_bridge.type = SVWRKS_LE; + return serverworks_setup(bridge_dev); + + default: + if(agp_try_unsupported) { + agp_bridge.type = SVWRKS_GENERIC; + return serverworks_setup(bridge_dev); + } + break; + } + } + +#endif /* CONFIG_AGP_SWORKS */ + /* find capndx */ pci_read_config_dword(dev, 0x04, &scratch); if (!(scratch & 0x00100000)) diff --git a/drivers/char/drm/agpsupport.c b/drivers/char/drm/agpsupport.c index c996df8f4dc8..5c61982d5c9b 100644 --- a/drivers/char/drm/agpsupport.c +++ b/drivers/char/drm/agpsupport.c @@ -284,6 +284,17 @@ drm_agp_head_t *drm_agp_init(void) case AMD_IRONGATE: head->chipset = "AMD Irongate"; break; case ALI_GENERIC: head->chipset = "ALi"; break; case ALI_M1541: head->chipset = "ALi M1541"; break; + case ALI_M1621: head->chipset = "ALi M1621"; break; + case ALI_M1631: head->chipset = "ALi M1631"; break; + case ALI_M1632: head->chipset = "ALi M1632"; break; + case ALI_M1641: head->chipset = "ALi M1641"; break; + case ALI_M1647: head->chipset = "ALi M1647"; break; + case ALI_M1651: head->chipset = "ALi M1651"; break; + case SVWRKS_GENERIC: head->chipset = "Serverworks Generic"; + break; + case SVWRKS_HE: head->chipset = "Serverworks HE"; + case SVWRKS_LE: head->chipset = "Serverworks LE"; + default: head->chipset = "Unknown"; break; } DRM_INFO("AGP %d.%d on %s @ 0x%08lx %ZuMB\n", diff --git a/drivers/char/i810-tco.c b/drivers/char/i810-tco.c index b7e3d1953d25..f50faa22cdc5 100644 --- a/drivers/char/i810-tco.c +++ b/drivers/char/i810-tco.c @@ -289,7 +289,7 @@ static unsigned char i810tco_getdevice (void) pci_write_config_byte (i810tco_pci, 0xd4, val1); pci_read_config_byte (i810tco_pci, 0xd4, &val1); if (val1 & 0x02) { - printk (KERN_ERR "i810tco init: failed to reset NO_REBOOT flag\n"); + printk (KERN_ERR "i810tco init: failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); return 0; /* Cannot reset NO_REBOOT bit */ } } diff --git a/drivers/char/random.c b/drivers/char/random.c index 5737e797daf0..b8c65c11de43 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -712,8 +712,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) #if defined (__i386__) if ( test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability) ) { __u32 high; - __asm__(".byte 0x0f,0x31" - :"=a" (time), "=d" (high)); + rdtsc(time, high); num ^= high; } else { time = jiffies; diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index ae2b6ddeea13..e958383673cc 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -485,14 +485,10 @@ static void rp_do_poll(unsigned long dummy) unsigned char CtlMask, AiopMask; #ifdef TIME_STAT - unsigned long low=0, high=0, loop_time; + unsigned long loop_time; unsigned long long time_stat_tmp=0, time_stat_tmp2=0; - __asm__(".byte 0x0f,0x31" - :"=a" (low), "=d" (high)); - time_stat_tmp = high; - time_stat_tmp <<= 32; - time_stat_tmp += low; + rdtscll(time_stat_tmp); #endif /* TIME_STAT */ for (ctrl=0; ctrl < max_board; ctrl++) { @@ -532,11 +528,7 @@ static void rp_do_poll(unsigned long dummy) mod_timer(&rocket_timer, jiffies + 1); } #ifdef TIME_STAT - __asm__(".byte 0x0f,0x31" - :"=a" (low), "=d" (high)); - time_stat_tmp2 = high; - time_stat_tmp2 <<= 32; - time_stat_tmp2 += low; + rdtscll(time_stat_tmp2); time_stat_tmp2 -= time_stat_tmp; time_stat += time_stat_tmp2; if (time_counter == 0) diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index fef02c4e61db..20d3ea15717e 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1872,6 +1872,8 @@ static void __do_SAK(void *arg) */ void do_SAK(struct tty_struct *tty) { + if (!tty) + return; PREPARE_TQUEUE(&tty->SAK_tq, __do_SAK, tty); schedule_task(&tty->SAK_tq); } diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in index 91af79e4a7e4..567a123b428d 100644 --- a/drivers/isdn/Config.in +++ b/drivers/isdn/Config.in @@ -105,6 +105,10 @@ if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then fi fi +if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then + dep_tristate 'Auvertech TurboPAM support' CONFIG_ISDN_DRV_TPAM $CONFIG_ISDN $CONFIG_PCI +fi + # CAPI subsystem tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index fc08d752a4aa..a30e5f9709d2 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile @@ -43,6 +43,7 @@ subdir-$(CONFIG_ISDN_DRV_LOOP) += isdnloop subdir-$(CONFIG_ISDN_DRV_ACT2000) += act2000 subdir-$(CONFIG_ISDN_DRV_EICON) += eicon subdir-$(CONFIG_HYSDN) += hysdn +subdir-$(CONFIG_ISDN_DRV_TPAM) += tpam obj-y += $(addsuffix /vmlinux-obj.o, $(subdir-y)) diff --git a/drivers/isdn/hisax/amd7930.c b/drivers/isdn/hisax/amd7930.c index 95b2111e3668..c6cf3dd2df05 100644 --- a/drivers/isdn/hisax/amd7930.c +++ b/drivers/isdn/hisax/amd7930.c @@ -1,4 +1,4 @@ -/* $Id: amd7930.c,v 1.5.6.1 2001/02/16 16:43:25 kai Exp $ +/* $Id: amd7930.c,v 1.5.6.3 2001/06/11 22:08:37 kai Exp $ * * HiSax ISDN driver - chip specific routines for AMD 7930 * @@ -94,7 +94,7 @@ #include "rawhdlc.h" #include <linux/interrupt.h> -static const char *amd7930_revision = "$Revision: 1.5.6.1 $"; +static const char *amd7930_revision = "$Revision: 1.5.6.3 $"; #define RCV_BUFSIZE 1024 /* Size of raw receive buffer in bytes */ #define RCV_BUFBLKS 4 /* Number of blocks to divide buffer into @@ -362,12 +362,8 @@ Bchan_close(struct BCState *bcs) amd7930_bclose(0, bcs->channel); if (test_bit(BC_FLG_INIT, &bcs->Flag)) { - while ((skb = skb_dequeue(&bcs->rqueue))) { - dev_kfree_skb(skb); - } - while ((skb = skb_dequeue(&bcs->squeue))) { - dev_kfree_skb(skb); - } + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); } test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); } diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index b895778db315..f4b13f07bcf7 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -1,4 +1,4 @@ -/* $Id: avm_pci.c,v 1.22.6.4 2001/02/16 16:43:25 kai Exp $ +/* $Id: avm_pci.c,v 1.22.6.5 2001/06/09 15:14:16 kai Exp $ * * avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards * Thanks to AVM, Berlin for informations @@ -18,7 +18,7 @@ #include <linux/interrupt.h> extern const char *CardType[]; -static const char *avm_pci_rev = "$Revision: 1.22.6.4 $"; +static const char *avm_pci_rev = "$Revision: 1.22.6.5 $"; #define AVM_FRITZ_PCI 1 #define AVM_FRITZ_PNP 2 @@ -591,8 +591,8 @@ close_hdlcstate(struct BCState *bcs) kfree(bcs->blog); bcs->blog = NULL; } - discard_queue(&bcs->rqueue); - discard_queue(&bcs->squeue); + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c index d3de5bd4eaa9..2f25292320e7 100644 --- a/drivers/isdn/hisax/callc.c +++ b/drivers/isdn/hisax/callc.c @@ -1,4 +1,4 @@ -/* $Id: callc.c,v 2.51.6.3 2001/05/26 15:19:57 kai Exp $ +/* $Id: callc.c,v 2.51.6.4 2001/06/09 15:14:17 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -20,7 +20,7 @@ #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module)) #endif /* MODULE */ -const char *lli_revision = "$Revision: 2.51.6.3 $"; +const char *lli_revision = "$Revision: 2.51.6.4 $"; extern struct IsdnCard cards[]; extern int nrcards; @@ -66,19 +66,6 @@ hisax_findcard(int driverid) return (struct IsdnCardState *) 0; } -int -discard_queue(struct sk_buff_head *q) -{ - struct sk_buff *skb; - int ret=0; - - while ((skb = skb_dequeue(q))) { - dev_kfree_skb(skb); - ret++; - } - return(ret); -} - static void link_debug(struct Channel *chanp, int direction, char *fmt, ...) { diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index 9a8d573d3848..b1a79f166734 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -1,4 +1,4 @@ -/* $Id: config.c,v 2.57.6.14 2001/05/26 15:19:57 kai Exp $ +/* $Id: config.c,v 2.57.6.15 2001/06/09 15:14:17 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -837,8 +837,8 @@ closecard(int cardnr) csta->bcs->BC_Close(csta->bcs); } - discard_queue(&csta->rq); - discard_queue(&csta->sq); + skb_queue_purge(&csta->rq); + skb_queue_purge(&csta->sq); if (csta->rcvbuf) { kfree(csta->rcvbuf); csta->rcvbuf = NULL; @@ -1333,7 +1333,7 @@ HiSax_reportcard(int cardnr, int sel) static int __init HiSax_init(void) { int i, retval; -#ifdef MODULE +#ifdef MODULE int j; int nzproto = 0; #endif @@ -1505,7 +1505,7 @@ static int __init HiSax_init(void) retval = -EIO; goto out_isdnl1; } - + return 0; out_isdnl1: diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c index 0440e427870b..53616888bbcd 100644 --- a/drivers/isdn/hisax/elsa_ser.c +++ b/drivers/isdn/hisax/elsa_ser.c @@ -1,4 +1,4 @@ -/* $Id: elsa_ser.c,v 2.10.6.1 2001/02/16 16:43:26 kai Exp $ +/* $Id: elsa_ser.c,v 2.10.6.2 2001/06/09 15:14:17 kai Exp $ * * stuff for the serial modem on ELSA cards * @@ -439,8 +439,6 @@ extern void hscx_l2l1(struct PStack *st, int pr, void *arg); void close_elsastate(struct BCState *bcs) { - struct sk_buff *skb; - modehscx(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { if (bcs->hw.hscx.rcvbuf) { @@ -448,12 +446,8 @@ close_elsastate(struct BCState *bcs) kfree(bcs->hw.hscx.rcvbuf); bcs->hw.hscx.rcvbuf = NULL; } - while ((skb = skb_dequeue(&bcs->rqueue))) { - dev_kfree_skb_any(skb); - } - while ((skb = skb_dequeue(&bcs->squeue))) { - dev_kfree_skb_any(skb); - } + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c index 5472c301c961..b33dedaaaae1 100644 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ b/drivers/isdn/hisax/hfc_2bds0.c @@ -1,4 +1,4 @@ -/* $Id: hfc_2bds0.c,v 1.15.6.1 2001/02/16 16:43:26 kai Exp $ +/* $Id: hfc_2bds0.c,v 1.15.6.2 2001/06/09 15:14:17 kai Exp $ * * specific routines for CCD's HFC 2BDS0 * @@ -568,8 +568,8 @@ close_2bs0(struct BCState *bcs) { mode_2bs0(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - discard_queue(&bcs->rqueue); - discard_queue(&bcs->squeue); + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c index 7bb82c77ed95..bd3167f4d569 100644 --- a/drivers/isdn/hisax/hfc_2bs0.c +++ b/drivers/isdn/hisax/hfc_2bs0.c @@ -1,4 +1,4 @@ -/* $Id: hfc_2bs0.c,v 1.17.6.1 2001/02/16 16:43:27 kai Exp $ +/* $Id: hfc_2bs0.c,v 1.17.6.2 2001/06/09 15:14:17 kai Exp $ * * specific routines for CCD's HFC 2BS0 * @@ -532,8 +532,8 @@ close_hfcstate(struct BCState *bcs) { mode_hfc(bcs, 0, bcs->channel); if (test_bit(BC_FLG_INIT, &bcs->Flag)) { - discard_queue(&bcs->rqueue); - discard_queue(&bcs->squeue); + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 54a3ba039d6c..33b1bd104f81 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.34.6.5 2001/04/08 19:32:26 kai Exp $ +/* $Id: hfc_pci.c,v 1.34.6.6 2001/06/09 15:14:17 kai Exp $ * hfc_pci.c low level driver for CCD´s hfc-pci based cards * @@ -35,7 +35,7 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.34.6.5 $"; +static const char *hfcpci_revision = "$Revision: 1.34.6.6 $"; /* table entry in the PCI devices list */ typedef struct { @@ -1497,8 +1497,8 @@ close_hfcpci(struct BCState *bcs) { mode_hfcpci(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - discard_queue(&bcs->rqueue); - discard_queue(&bcs->squeue); + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index ef8ed461a17d..f4a77a41472e 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -1,4 +1,4 @@ -/* $Id: hfc_sx.c,v 1.9 2000/11/24 17:05:37 kai Exp $ +/* $Id: hfc_sx.c,v 1.9.6.1 2001/06/09 15:14:17 kai Exp $ * hfc_sx.c low level driver for CCD´s hfc-s+/sp based cards * @@ -32,7 +32,7 @@ extern const char *CardType[]; -static const char *hfcsx_revision = "$Revision: 1.9 $"; +static const char *hfcsx_revision = "$Revision: 1.9.6.1 $"; /***************************************/ /* IRQ-table for CCDs demo board */ @@ -1288,8 +1288,8 @@ close_hfcsx(struct BCState *bcs) { mode_hfcsx(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - discard_queue(&bcs->rqueue); - discard_queue(&bcs->squeue); + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index f8e61f1fef2f..25196db87c7c 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -1,4 +1,4 @@ -/* $Id: hisax.h,v 2.52.6.5 2001/05/26 15:19:57 kai Exp $ +/* $Id: hisax.h,v 2.52.6.6 2001/06/09 15:14:17 kai Exp $ * * Basic declarations, defines and prototypes * @@ -1325,7 +1325,6 @@ int QuickHex(char *txt, u_char * p, int cnt); void LogFrame(struct IsdnCardState *cs, u_char * p, int size); void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir); void iecpy(u_char * dest, u_char * iestart, int ieoffset); -int discard_queue(struct sk_buff_head *q); #ifdef ISDN_CHIP_ISAC void setstack_isac(struct PStack *st, struct IsdnCardState *cs); #endif /* ISDN_CHIP_ISAC */ diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c index a39e1321e894..d527d804c079 100644 --- a/drivers/isdn/hisax/hscx.c +++ b/drivers/isdn/hisax/hscx.c @@ -1,4 +1,4 @@ -/* $Id: hscx.c,v 1.21.6.1 2001/02/16 16:43:27 kai Exp $ +/* $Id: hscx.c,v 1.21.6.2 2001/06/09 15:14:17 kai Exp $ * * hscx.c HSCX specific routines * @@ -166,8 +166,8 @@ close_hscxstate(struct BCState *bcs) kfree(bcs->blog); bcs->blog = NULL; } - discard_queue(&bcs->rqueue); - discard_queue(&bcs->squeue); + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c index a9da7f72f58d..609f626d5794 100644 --- a/drivers/isdn/hisax/icc.c +++ b/drivers/isdn/hisax/icc.c @@ -1,4 +1,4 @@ -// $Id: icc.c,v 1.5.6.2 2001/03/13 16:17:08 kai Exp $ +// $Id: icc.c,v 1.5.6.3 2001/06/09 15:14:17 kai Exp $ //----------------------------------------------------------------------------- // // ICC specific routines @@ -551,8 +551,8 @@ ICC_l1hw(struct PStack *st, int pr, void *arg) } break; case (HW_DEACTIVATE | RESPONSE): - discard_queue(&cs->rq); - discard_queue(&cs->sq); + skb_queue_purge(&cs->rq); + skb_queue_purge(&cs->sq); if (cs->tx_skb) { dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c index 3e6c9525a705..b581c28724cf 100644 --- a/drivers/isdn/hisax/isac.c +++ b/drivers/isdn/hisax/isac.c @@ -1,4 +1,4 @@ -/* $Id: isac.c,v 1.28.6.1 2001/02/16 16:43:27 kai Exp $ +/* $Id: isac.c,v 1.28.6.2 2001/06/09 15:14:17 kai Exp $ * * isac.c ISAC specific routines * @@ -549,8 +549,8 @@ ISAC_l1hw(struct PStack *st, int pr, void *arg) } break; case (HW_DEACTIVATE | RESPONSE): - discard_queue(&cs->rq); - discard_queue(&cs->sq); + skb_queue_purge(&cs->rq); + skb_queue_purge(&cs->sq); if (cs->tx_skb) { dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index f2b9a5423327..aede8b81c577 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -1,4 +1,4 @@ -/* $Id: isar.c,v 1.17.6.2 2001/04/08 17:51:42 kai Exp $ +/* $Id: isar.c,v 1.17.6.3 2001/06/09 15:14:17 kai Exp $ * * isar.c ISAR (Siemens PSB 7110) specific routines * @@ -1650,8 +1650,8 @@ close_isarstate(struct BCState *bcs) kfree(bcs->hw.isar.rcvbuf); bcs->hw.isar.rcvbuf = NULL; } - discard_queue(&bcs->rqueue); - discard_queue(&bcs->squeue); + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c index 3e3427575f11..792f9567d679 100644 --- a/drivers/isdn/hisax/isdnl1.c +++ b/drivers/isdn/hisax/isdnl1.c @@ -736,7 +736,7 @@ static struct FsmNode L1BFnList[] __initdata = #define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode)) -int __init +int __init Isdnl1New(void) { int retval; diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c index cee558c4f575..18683236802f 100644 --- a/drivers/isdn/hisax/isdnl2.c +++ b/drivers/isdn/hisax/isdnl2.c @@ -1,4 +1,4 @@ -/* $Id: isdnl2.c,v 2.25.6.2 2001/05/26 15:19:57 kai Exp $ +/* $Id: isdnl2.c,v 2.25.6.3 2001/06/09 15:14:17 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -16,7 +16,7 @@ #include "hisax.h" #include "isdnl2.h" -const char *l2_revision = "$Revision: 2.25.6.2 $"; +const char *l2_revision = "$Revision: 2.25.6.3 $"; static void l2m_debug(struct FsmInst *fi, char *fmt, ...); @@ -649,7 +649,7 @@ l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_queue(&st->l2.i_queue); + skb_queue_purge(&st->l2.i_queue); test_and_set_bit(FLG_L3_INIT, &st->l2.flag); test_and_clear_bit(FLG_PEND_REL, &st->l2.flag); } @@ -659,7 +659,7 @@ l2_l3_reestablish(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_queue(&st->l2.i_queue); + skb_queue_purge(&st->l2.i_queue); establishlink(fi); test_and_set_bit(FLG_L3_INIT, &st->l2.flag); } @@ -685,7 +685,7 @@ l2_disconnect(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_queue(&st->l2.i_queue); + skb_queue_purge(&st->l2.i_queue); freewin(st); FsmChangeState(fi, ST_L2_6); st->l2.rc = 0; @@ -745,7 +745,7 @@ l2_restart_multi(struct FsmInst *fi, int event, void *arg) st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'F'); if (st->l2.vs != st->l2.va) { - discard_queue(&st->l2.i_queue); + skb_queue_purge(&st->l2.i_queue); est = 1; } @@ -778,7 +778,7 @@ l2_stop_multi(struct FsmInst *fi, int event, void *arg) send_uframe(st, UA | get_PollFlagFree(st, skb), RSP); - discard_queue(&st->l2.i_queue); + skb_queue_purge(&st->l2.i_queue); freewin(st); lapb_dl_release_l2l3(st, INDICATION); } @@ -802,7 +802,7 @@ l2_connected(struct FsmInst *fi, int event, void *arg) if (test_and_clear_bit(FLG_L3_INIT, &st->l2.flag)) { pr = DL_ESTABLISH | CONFIRM; } else if (st->l2.vs != st->l2.va) { - discard_queue(&st->l2.i_queue); + skb_queue_purge(&st->l2.i_queue); pr = DL_ESTABLISH | INDICATION; } @@ -860,7 +860,7 @@ l2_st5_dm_release(struct FsmInst *fi, int event, void *arg) if (get_PollFlagFree(st, skb)) { stop_t200(st, 7); if (!test_bit(FLG_L3_INIT, &st->l2.flag)) - discard_queue(&st->l2.i_queue); + skb_queue_purge(&st->l2.i_queue); if (test_bit(FLG_LAPB, &st->l2.flag)) st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); st5_dl_release_l2l3(st); @@ -1156,7 +1156,7 @@ l2_st5_tout_200(struct FsmInst *fi, int event, void *arg) } else if (st->l2.rc == st->l2.N200) { FsmChangeState(fi, ST_L2_4); test_and_clear_bit(FLG_T200_RUN, &st->l2.flag); - discard_queue(&st->l2.i_queue); + skb_queue_purge(&st->l2.i_queue); st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'G'); if (test_bit(FLG_LAPB, &st->l2.flag)) st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); @@ -1388,7 +1388,7 @@ l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_queue(&st->l2.ui_queue); + skb_queue_purge(&st->l2.ui_queue); st->l2.tei = -1; FsmChangeState(fi, ST_L2_1); } @@ -1398,7 +1398,7 @@ l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_queue(&st->l2.ui_queue); + skb_queue_purge(&st->l2.ui_queue); st->l2.tei = -1; st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); FsmChangeState(fi, ST_L2_1); @@ -1409,8 +1409,8 @@ l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_queue(&st->l2.i_queue); - discard_queue(&st->l2.ui_queue); + skb_queue_purge(&st->l2.i_queue); + skb_queue_purge(&st->l2.ui_queue); freewin(st); st->l2.tei = -1; stop_t200(st, 17); @@ -1423,7 +1423,7 @@ l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_queue(&st->l2.ui_queue); + skb_queue_purge(&st->l2.ui_queue); st->l2.tei = -1; stop_t200(st, 18); st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); @@ -1435,8 +1435,8 @@ l2_tei_remove(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_queue(&st->l2.i_queue); - discard_queue(&st->l2.ui_queue); + skb_queue_purge(&st->l2.i_queue); + skb_queue_purge(&st->l2.ui_queue); freewin(st); st->l2.tei = -1; stop_t200(st, 17); @@ -1450,8 +1450,8 @@ l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_queue(&st->l2.i_queue); - discard_queue(&st->l2.ui_queue); + skb_queue_purge(&st->l2.i_queue); + skb_queue_purge(&st->l2.ui_queue); if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag)) st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); } @@ -1461,8 +1461,8 @@ l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_queue(&st->l2.i_queue); - discard_queue(&st->l2.ui_queue); + skb_queue_purge(&st->l2.i_queue); + skb_queue_purge(&st->l2.ui_queue); freewin(st); stop_t200(st, 19); st5_dl_release_l2l3(st); @@ -1474,7 +1474,7 @@ l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_queue(&st->l2.ui_queue); + skb_queue_purge(&st->l2.ui_queue); stop_t200(st, 20); st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); FsmChangeState(fi, ST_L2_4); @@ -1485,8 +1485,8 @@ l2_persistant_da(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_queue(&st->l2.i_queue); - discard_queue(&st->l2.ui_queue); + skb_queue_purge(&st->l2.i_queue); + skb_queue_purge(&st->l2.ui_queue); freewin(st); stop_t200(st, 19); FsmDelTimer(&st->l2.t203, 19); @@ -1761,8 +1761,8 @@ releasestack_isdnl2(struct PStack *st) { FsmDelTimer(&st->l2.t200, 21); FsmDelTimer(&st->l2.t203, 16); - discard_queue(&st->l2.i_queue); - discard_queue(&st->l2.ui_queue); + skb_queue_purge(&st->l2.i_queue); + skb_queue_purge(&st->l2.ui_queue); ReleaseWin(&st->l2); } diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c index 0ecd9cfb33be..5eaa9bfad15b 100644 --- a/drivers/isdn/hisax/isdnl3.c +++ b/drivers/isdn/hisax/isdnl3.c @@ -1,4 +1,4 @@ -/* $Id: isdnl3.c,v 2.17.6.3 2001/05/26 15:19:57 kai Exp $ +/* $Id: isdnl3.c,v 2.17.6.4 2001/06/09 15:14:17 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -18,7 +18,7 @@ #include "isdnl3.h" #include <linux/config.h> -const char *l3_revision = "$Revision: 2.17.6.3 $"; +const char *l3_revision = "$Revision: 2.17.6.4 $"; static struct Fsm l3fsm; @@ -404,7 +404,7 @@ releasestack_isdnl3(struct PStack *st) st->l3.global = NULL; } FsmDelTimer(&st->l3.l3m_timer, 54); - discard_queue(&st->l3.squeue); + skb_queue_purge(&st->l3.squeue); } void @@ -520,7 +520,7 @@ lc_release_ind(struct FsmInst *fi, int event, void *arg) FsmDelTimer(&st->l3.l3m_timer, 52); FsmChangeState(fi, ST_L3_LC_REL); - discard_queue(&st->l3.squeue); + skb_queue_purge(&st->l3.squeue); l3ml3p(st, DL_RELEASE | INDICATION); } @@ -530,7 +530,7 @@ lc_release_cnf(struct FsmInst *fi, int event, void *arg) struct PStack *st = fi->userdata; FsmChangeState(fi, ST_L3_LC_REL); - discard_queue(&st->l3.squeue); + skb_queue_purge(&st->l3.squeue); l3ml3p(st, DL_RELEASE | CONFIRM); } diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c index 706b0855cb34..8b53fcc09160 100644 --- a/drivers/isdn/hisax/jade.c +++ b/drivers/isdn/hisax/jade.c @@ -1,4 +1,4 @@ -/* $Id: jade.c,v 1.6.6.1 2001/02/16 16:43:27 kai Exp $ +/* $Id: jade.c,v 1.6.6.2 2001/06/09 15:14:18 kai Exp $ * * jade.c JADE stuff (derived from original hscx.c) * @@ -209,8 +209,8 @@ close_jadestate(struct BCState *bcs) kfree(bcs->blog); bcs->blog = NULL; } - discard_queue(&bcs->rqueue); - discard_queue(&bcs->squeue); + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; diff --git a/drivers/isdn/hisax/md b/drivers/isdn/hisax/md new file mode 100644 index 000000000000..5efa612cfe71 --- /dev/null +++ b/drivers/isdn/hisax/md @@ -0,0 +1,12 @@ +6f9433a8b696076562562d090e3c420f isac.c +13c3eed869f5139f44c563e3a8fea1f5 isdnl1.c +addcff863b0ff1e366c0f2ae9fa6e81e isdnl2.c +7076deb94a363945c21ea27aca4a720a isdnl3.c +51c603829b6cc4f8421f744ad657ceff tei.c +669050ab5079f02887ed0239d86e5474 callc.c +e592db58630c1f1029cc064110108156 cert.c +fadeb3b85bb23bc1ac48470c0848d6fa l3dss1.c +cf7dec9fac6283716904d26b99188476 l3_1tr6.c +65d9e5471bc129624f858ebcf0743525 elsa.c +b4cf8a4dceed9ea6dcba65a85b4eecc7 diva.c +99e67bea8f6945fa0d4e0aded5bf0fa0 sedlbauer.c diff --git a/drivers/isdn/hisax/md5sums.asc b/drivers/isdn/hisax/md5sums.asc index b7990826edb5..f658ab4efd58 100644 --- a/drivers/isdn/hisax/md5sums.asc +++ b/drivers/isdn/hisax/md5sums.asc @@ -7,12 +7,12 @@ # cards in the moment. # Read ../../../Documentation/isdn/HiSax.cert for more informations. # -9663cc9f4374c361197d394f6d27c459 isac.c +6f9433a8b696076562562d090e3c420f isac.c 13c3eed869f5139f44c563e3a8fea1f5 isdnl1.c -64dcc220ae42fe9e4bbc664c9525bd0a isdnl2.c -700aa997e04f5e7e0d32f0d60c8e7fa9 isdnl3.c +addcff863b0ff1e366c0f2ae9fa6e81e isdnl2.c +7076deb94a363945c21ea27aca4a720a isdnl3.c 51c603829b6cc4f8421f744ad657ceff tei.c -144d646162d83bb5b99095917d131865 callc.c +669050ab5079f02887ed0239d86e5474 callc.c e592db58630c1f1029cc064110108156 cert.c fadeb3b85bb23bc1ac48470c0848d6fa l3dss1.c cf7dec9fac6283716904d26b99188476 l3_1tr6.c @@ -21,13 +21,3 @@ b4cf8a4dceed9ea6dcba65a85b4eecc7 diva.c 99e67bea8f6945fa0d4e0aded5bf0fa0 sedlbauer.c # end of md5sums ------BEGIN PGP SIGNATURE----- -Version: 2.6.3in -Charset: noconv - -iQCVAwUBOxFX6zpxHvX/mS9tAQE+bgP7B5FFxU+RQ3l8fBvZoMbu/Mslo9+XgtLg -gK8Xwnp4Ij909fa2i6i2bvFPkzHULMqp2PRdtxBTn9CdhwSZyRByhCvZvDHitsv2 -ZEIRn2Bd1jhhgWcr5KCbjKUaIwcFY7RdSQJw/yCyGsodg1fLI+g+QrnMkICI/RTa -AtYLLWgwEqo= -=3IMV ------END PGP SIGNATURE----- diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c index 23ebd3c9b296..d94bccd4eb45 100644 --- a/drivers/isdn/hisax/netjet.c +++ b/drivers/isdn/hisax/netjet.c @@ -1,4 +1,4 @@ -/* $Id: netjet.c,v 1.24.6.4 2001/02/16 16:43:28 kai Exp $ +/* $Id: netjet.c,v 1.24.6.5 2001/06/09 15:14:18 kai Exp $ * * netjet.c low level stuff for Traverse Technologie NETJet ISDN cards * @@ -22,7 +22,7 @@ #include <asm/io.h> #include "netjet.h" -const char *NETjet_revision = "$Revision: 1.24.6.4 $"; +const char *NETjet_revision = "$Revision: 1.24.6.5 $"; /* Interface functions */ @@ -880,8 +880,8 @@ close_tigerstate(struct BCState *bcs) kfree(bcs->hw.tiger.sendbuf); bcs->hw.tiger.sendbuf = NULL; } - discard_queue(&bcs->rqueue); - discard_queue(&bcs->squeue); + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index 9629efb5fe19..ae719d50fea9 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -1,4 +1,4 @@ -/* $Id: w6692.c,v 1.12.6.4 2001/02/16 16:43:29 kai Exp $ +/* $Id: w6692.c,v 1.12.6.5 2001/06/09 15:14:18 kai Exp $ * * w6692.c Winbond W6692 specific routines * @@ -35,7 +35,7 @@ static const PCI_ENTRY id_list[] = extern const char *CardType[]; -const char *w6692_revision = "$Revision: 1.12.6.4 $"; +const char *w6692_revision = "$Revision: 1.12.6.5 $"; #define DBUSY_TIMER_VALUE 80 @@ -641,8 +641,8 @@ W6692_l1hw(struct PStack *st, int pr, void *arg) /* !!! not implemented yet */ break; case (HW_DEACTIVATE | RESPONSE): - discard_queue(&cs->rq); - discard_queue(&cs->sq); + skb_queue_purge(&cs->rq); + skb_queue_purge(&cs->sq); if (cs->tx_skb) { dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; @@ -805,8 +805,8 @@ close_w6692state(struct BCState *bcs) kfree(bcs->blog); bcs->blog = NULL; } - discard_queue(&bcs->rqueue); - discard_queue(&bcs->squeue); + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index e864ff8f7b06..e1a117dbce51 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.65.6.4 2001/04/20 02:42:01 keil Exp $ +/* $Id: icn.c,v 1.65.6.5 2001/06/09 15:14:19 kai Exp $ * ISDN low-level module for the ICN active ISDN-Card. * @@ -34,7 +34,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.65.6.4 $"; +*revision = "$Revision: 1.65.6.5 $"; static int icn_addcard(int, char *, char *); @@ -51,8 +51,7 @@ icn_free_queue(icn_card * card, int channel) struct sk_buff *skb; unsigned long flags; - while ((skb = skb_dequeue(queue))) - dev_kfree_skb(skb); + skb_queue_purge(queue); save_flags(flags); cli(); card->xlen[channel] = 0; diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index a8b9b6521f45..9100741b68a6 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.114.6.11 2001/04/20 02:41:58 keil Exp $ +/* $Id: isdn_common.c,v 1.114.6.12 2001/06/09 15:14:15 kai Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -51,7 +51,7 @@ isdn_dev *dev; -static char *isdn_revision = "$Revision: 1.114.6.11 $"; +static char *isdn_revision = "$Revision: 1.114.6.12 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -233,20 +233,6 @@ int isdn_msncmp( const char * msn1, const char * msn2 ) return isdn_wildmat( TmpMsn1, TmpMsn2 ); } -static void -isdn_free_queue(struct sk_buff_head *queue) -{ - struct sk_buff *skb; - unsigned long flags; - - save_flags(flags); - cli(); - if (skb_queue_len(queue)) - while ((skb = skb_dequeue(queue))) - dev_kfree_skb(skb); - restore_flags(flags); -} - int isdn_dc2minor(int di, int ch) { @@ -739,7 +725,7 @@ isdn_status_callback(isdn_ctrl * c) kfree(dev->drv[di]->rcverr); kfree(dev->drv[di]->rcvcount); for (i = 0; i < dev->drv[di]->channels; i++) - isdn_free_queue(&dev->drv[di]->rpqueue[i]); + skb_queue_purge(&dev->drv[di]->rpqueue[i]); kfree(dev->drv[di]->rpqueue); kfree(dev->drv[di]->rcv_waitq); kfree(dev->drv[di]); @@ -1873,7 +1859,7 @@ isdn_free_channel(int di, int ch, int usage) dev->v110[i] = NULL; // 20.10.99 JIM, try to reinitialize v110 ! isdn_info_update(); - isdn_free_queue(&dev->drv[di]->rpqueue[ch]); + skb_queue_purge(&dev->drv[di]->rpqueue[ch]); } restore_flags(flags); } @@ -2036,7 +2022,7 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding) if ((adding) && (d->rpqueue)) { for (j = 0; j < d->channels; j++) - isdn_free_queue(&d->rpqueue[j]); + skb_queue_purge(&d->rpqueue[j]); kfree(d->rpqueue); } if (!(d->rpqueue = diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index 9d724844fbc8..123b9d369582 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.140.6.4 2001/04/20 02:41:58 keil Exp $ +/* $Id: isdn_net.c,v 1.140.6.6 2001/06/11 22:08:37 kai Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -190,7 +190,7 @@ static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); static void isdn_net_ciscohdlck_connected(isdn_net_local *lp); static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp); -char *isdn_net_revision = "$Revision: 1.140.6.4 $"; +char *isdn_net_revision = "$Revision: 1.140.6.6 $"; /* * Code for raw-networking over ISDN @@ -301,13 +301,11 @@ static void isdn_net_unbind_channel(isdn_net_local * lp) { ulong flags; - struct sk_buff *skb; save_flags(flags); cli(); - while ((skb = skb_dequeue(&lp->super_tx_queue))) { - kfree_skb(skb); - } + skb_queue_purge(&lp->super_tx_queue); + if (!lp->master) { /* reset only master device */ /* Moral equivalent of dev_purge_queues(): BEWARE! This chunk of code cannot be called from hardware diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c index 5dba67d1427c..e95beb90ba60 100644 --- a/drivers/isdn/isdn_tty.c +++ b/drivers/isdn/isdn_tty.c @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.94.6.1 2001/02/16 16:43:22 kai Exp $ +/* $Id: isdn_tty.c,v 1.94.6.2 2001/06/09 15:14:15 kai Exp $ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -66,7 +66,7 @@ static int bit2si[8] = static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.94.6.1 $"; +char *isdn_tty_revision = "$Revision: 1.94.6.2 $"; /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() @@ -307,18 +307,13 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb) void isdn_tty_cleanup_xmit(modem_info * info) { - struct sk_buff *skb; unsigned long flags; save_flags(flags); cli(); - if (skb_queue_len(&info->xmit_queue)) - while ((skb = skb_dequeue(&info->xmit_queue))) - kfree_skb(skb); + skb_queue_purge(&info->xmit_queue); #ifdef CONFIG_ISDN_AUDIO - if (skb_queue_len(&info->dtmf_queue)) - while ((skb = skb_dequeue(&info->dtmf_queue))) - kfree_skb(skb); + skb_queue_purge(&info->dtmf_queue); #endif restore_flags(flags); } diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index 3fb82bfa8d99..64e60e3bef7b 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -1,4 +1,4 @@ -/* $Id: isdnloop.c,v 1.11.6.2 2001/02/16 16:43:32 kai Exp $ +/* $Id: isdnloop.c,v 1.11.6.3 2001/06/09 15:14:19 kai Exp $ * ISDN low-level module implementing a dummy loop driver. * @@ -26,7 +26,7 @@ #include "isdnloop.h" static char -*revision = "$Revision: 1.11.6.2 $"; +*revision = "$Revision: 1.11.6.3 $"; static int isdnloop_addcard(char *); @@ -41,10 +41,8 @@ static void isdnloop_free_queue(isdnloop_card * card, int channel) { struct sk_buff_head *queue = &card->bqueue[channel]; - struct sk_buff *skb; - while ((skb = skb_dequeue(queue))) - dev_kfree_skb(skb); + skb_queue_purge(queue); card->sndcount[channel] = 0; } @@ -1574,11 +1572,8 @@ isdnloop_exit(void) } card = cards; while (card) { - struct sk_buff *skb; - last = card; - while ((skb = skb_dequeue(&card->dqueue))) - dev_kfree_skb(skb); + skb_queue_purge(&card->dqueue); card = card->next; kfree(last); } diff --git a/drivers/isdn/tpam/Makefile b/drivers/isdn/tpam/Makefile new file mode 100644 index 000000000000..bc1e6ca2e435 --- /dev/null +++ b/drivers/isdn/tpam/Makefile @@ -0,0 +1,21 @@ +# Makefile for the TurboPAM ISDN device driver + +# The target object and module list name. + +O_TARGET := vmlinux-obj.o + +# Multipart objects. + +list-multi := tpam.o +tpam-objs := tpam_main.o tpam_nco.o tpam_memory.o tpam_commands.o tpam_queues.o tpam_hdlc.o tpam_crcpc.o + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_DRV_TPAM) += tpam.o + +include $(TOPDIR)/Rules.make + +# Link rules for multi-part drivers. + +tpam.o: $(tpam-objs) + $(LD) -r -o $@ $(tpam-objs) diff --git a/drivers/isdn/tpam/tpam.h b/drivers/isdn/tpam/tpam.h new file mode 100644 index 000000000000..82c78b90025f --- /dev/null +++ b/drivers/isdn/tpam/tpam.h @@ -0,0 +1,246 @@ +/* $Id: tpam.h,v 1.1.2.1 2001/06/05 19:45:37 kai Exp $ + * + * Turbo PAM ISDN driver for Linux. (Kernel Driver) + * + * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * For all support questions please contact: <support@auvertech.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _TPAM_PRIV_H_ +#define _TPAM_PRIV_H_ + +#include <linux/module.h> +#include <linux/isdnif.h> +#include <linux/init.h> + +/* Maximum number of channels for this board */ +#define TPAM_NBCHANNEL 30 +/* Maximum size of data */ +#define TPAM_MAXBUFSIZE 2032 +/* Size of a page of board memory */ +#define TPAM_PAGE_SIZE 0x003ffffc /* 4 MB */ +/* Magic number present if the board was successfully started */ +#define TPAM_MAGICNUMBER 0x2a343242 + +/* Registers in the PCI BAR0 */ +#define TPAM_PAGE_REGISTER 0x00400000 /* Select page */ +#define TPAM_DSPINT_REGISTER 0x00400004 /* Interrupt board */ +#define TPAM_RESETPAM_REGISTER 0x00400008 /* Reset board */ +#define TPAM_HINTACK_REGISTER 0x0040000c /* Ack interrupt */ +#define TPAM_HPIC_REGISTER 0x00400014 /* Board ready */ + +/* Registers in the board memory */ +#define TPAM_MAGICNUMBER_REGISTER 0x80008000 /* Magic number */ +#define TPAM_EXID_REGISTER 0x80008004 /* EXID - not used */ +#define TPAM_UPLOADPTR_REGISTER 0x80008008 /* Upload data ptr */ +#define TPAM_DOWNLOADPTR_REGISTER 0x8000800c /* Download data ptr */ +#define TPAM_ACKUPLOAD_REGISTER 0x80008010 /* Ack upload */ +#define TPAM_ACKDOWNLOAD_REGISTER 0x80008014 /* Ack download */ +#define TPAM_INTERRUPTACK_REGISTER 0x80008018 /* Ack interrupt */ + +/* Reserved areas in the board memory */ +#define TPAM_RESERVEDAREA1_START 0x00000000 +#define TPAM_RESERVEDAREA1_END 0x003FFFFF +#define TPAM_RESERVEDAREA2_START 0x01C00000 +#define TPAM_RESERVEDAREA2_END 0x01FFFFFF +#define TPAM_RESERVEDAREA3_START 0x04000000 +#define TPAM_RESERVEDAREA3_END 0x7FFFFFFF +#define TPAM_RESERVEDAREA4_START 0x80010000 +#define TPAM_RESERVEDAREA4_END 0xFFFFFFFF + +/* NCO ID invalid */ +#define TPAM_NCOID_INVALID 0xffff +/* channel number invalid */ +#define TPAM_CHANNEL_INVALID 0xffff + +/* Channel structure */ +typedef struct tpam_channel { + int num; /* channel number */ + struct tpam_card *card; /* channel's card */ + u32 ncoid; /* ncoid */ + u8 hdlc; /* hdlc mode (set by user level) */ + u8 realhdlc; /* hdlc mode (negociated with peer) */ + u32 hdlcshift; /* hdlc shift */ + u8 readytoreceive; /* channel ready to receive data */ + struct sk_buff_head sendq; /* Send queue */ +} tpam_channel; + +/* Card structure */ +typedef struct tpam_card { + struct tpam_card *next; /* next card in list */ + unsigned int irq; /* IRQ used by this board */ + unsigned long bar0; /* ioremapped bar0 */ + int id; /* id of the board */ + isdn_if interface; /* isdn link-level pointer */ + int channels_used; /* number of channels actually used */ + int channels_tested; /* number of channels being tested */ + u8 loopmode; /* board in looptest mode */ + tpam_channel channels[TPAM_NBCHANNEL];/* channels tab */ + int running; /* card is running */ + int busy; /* waiting for ack from card */ + int roundrobin; /* round robin between channels */ + struct sk_buff_head sendq; /* send queue */ + struct sk_buff_head recvq; /* receive queue */ + struct tq_struct send_tq; /* send task queue */ + struct tq_struct recv_tq; /* receive task queue */ + spinlock_t lock; /* lock for the card */ +} tpam_card; + +/* Timeout waiting for signature to become available */ +#define SIGNATURE_TIMEOUT (5*HZ) +/* Timeout waiting for receiving all the ACreateNCOCnf */ +#define NCOCREATE_TIMEOUT (30*HZ) + +/* Maximum size of the TLV block */ +#define MPB_MAXIMUMBLOCKTLVSIZE 128 +/* Maximum size of the data block */ +#define MPB_MAXIMUMDATASIZE 4904 +/* Maximum size of a phone number */ +#define PHONE_MAXIMUMSIZE 32 + +/* Header for a sk_buff structure */ +typedef struct skb_header { + u16 size; /* size of pci_mpb block + size of tlv block */ + u16 data_size; /* size of the data block */ + u16 ack; /* packet needs to send ack upon send */ + u16 ack_size; /* size of data to be acknowledged upon send */ +} skb_header; + +/* PCI message header structure */ +typedef struct pci_mpb { + u16 exID; /* exID - not used */ + u16 flags; /* flags - not used */ + u32 errorCode; /* errorCode - not used */ + u16 messageID; /* message ID - one of ID_XXX */ + u16 maximumBlockTLVSize; /* MPB_MAXIMUMBLOCKTLVSIZE */ + u16 actualBlockTLVSize; /* size of the tlv block */ + u16 maximumDataSize; /* MPB_MAXIMUMDATASIZE */ + u16 actualDataSize; /* size of the data block */ + u16 dummy; /* padding */ +} pci_mpb; + +/* Types of PCI messages */ +#define ID_ACreateNCOReq 101 +#define ID_ACreateNCOCnf 102 +#define ID_ADestroyNCOReq 103 +#define ID_ADestroyNCOCnf 104 +#define ID_CConnectReq 203 +#define ID_CConnectInd 204 +#define ID_CConnectRsp 205 +#define ID_CConnectCnf 206 +#define ID_CDisconnectReq 207 +#define ID_CDisconnectInd 208 +#define ID_CDisconnectRsp 209 +#define ID_CDisconnectCnf 210 +#define ID_U3DataReq 307 +#define ID_U3DataInd 308 +#define ID_U3ReadyToReceiveInd 318 + +/* Parameters for the PCI message TLV block */ +#define PAR_BearerCap 3 +#define PAR_CalledNumber 7 +#define PAR_CallingNumber 11 +#define PAR_CauseToPUF 15 +#define PAR_Cdirection 16 +#define PAR_CompletionStatus 19 +#define PAR_Facility 30 +#define PAR_HLC 34 +#define PAR_NCOID 49 +#define PAR_NCOType 50 +#define PAR_ReadyFlag 55 +#define PAR_U3Protocol 62 +#define PAR_Udirection 64 + +/* Delayed statcallb structure */ +typedef struct tpam_statcallb_data { + tpam_card *card; /* card issuing the statcallb */ + struct timer_list *timer; /* timer launching the statcallb */ + isdn_ctrl ctrl; /* isdn command */ +} tpam_statcallb_data; + +/* Function prototypes from tpam_main.c */ +extern tpam_card *tpam_findcard(int); +extern u32 tpam_findchannel(tpam_card *, u32); + +/* Function prototypes from tpam_memory.c */ +extern void copy_to_pam_dword(tpam_card *, const void *, u32); +extern void copy_to_pam(tpam_card *, void *, const void *, u32); +extern u32 copy_from_pam_dword(tpam_card *, const void *); +extern void copy_from_pam(tpam_card *, void *, const void *, u32); +extern int copy_from_pam_to_user(tpam_card *, void *, const void *, u32); +extern int copy_from_user_to_pam(tpam_card *, void *, const void *, u32); +extern int tpam_verify_area(u32, u32); + +/* Function prototypes from tpam_nco.c */ +extern struct sk_buff *build_ACreateNCOReq(const u8 *); +extern struct sk_buff *build_ADestroyNCOReq(u32); +extern struct sk_buff *build_CConnectReq(u32, const u8 *, u8); +extern struct sk_buff *build_CConnectRsp(u32); +extern struct sk_buff *build_CDisconnectReq(u32); +extern struct sk_buff *build_CDisconnectRsp(u32); +extern struct sk_buff *build_U3DataReq(u32, void *, u16, u16, u16); +extern int parse_ACreateNCOCnf(struct sk_buff *, u8 *, u32 *); +extern int parse_ADestroyNCOCnf(struct sk_buff *, u8 *, u32 *); +extern int parse_CConnectCnf(struct sk_buff *, u32 *); +extern int parse_CConnectInd(struct sk_buff *, u32 *, u8 *, u8 *, + u8 *, u8 *, u8 *); +extern int parse_CDisconnectCnf(struct sk_buff *, u32 *, u32 *); +extern int parse_CDisconnectInd(struct sk_buff *, u32 *, u32 *); +extern int parse_U3ReadyToReceiveInd(struct sk_buff *, u32 *, u8 *); +extern int parse_U3DataInd(struct sk_buff *, u32 *, u8 **, u16 *); + +/* Function prototypes from tpam_queues.c */ +extern void tpam_enqueue(tpam_card *, struct sk_buff *); +extern void tpam_enqueue_data(tpam_channel *, struct sk_buff *); +extern void tpam_irq(int, void *, struct pt_regs *); +extern void tpam_recv_tq(tpam_card *); +extern void tpam_send_tq(tpam_card *); + +/* Function prototypes from tpam_commands.c */ +extern int tpam_command(isdn_ctrl *); +extern int tpam_writebuf_skb(int, int, int, struct sk_buff *); +extern void tpam_recv_ACreateNCOCnf(tpam_card *, struct sk_buff *); +extern void tpam_recv_ADestroyNCOCnf(tpam_card *, struct sk_buff *); +extern void tpam_recv_CConnectCnf(tpam_card *, struct sk_buff *); +extern void tpam_recv_CConnectInd(tpam_card *, struct sk_buff *); +extern void tpam_recv_CDisconnectInd(tpam_card *, struct sk_buff *); +extern void tpam_recv_CDisconnectCnf(tpam_card *, struct sk_buff *); +extern void tpam_recv_U3DataInd(tpam_card *, struct sk_buff *); +extern void tpam_recv_U3ReadyToReceiveInd(tpam_card *, struct sk_buff *); + +/* Function prototypes from tpam_hdlc.c */ +extern u32 hdlc_encode(u8 *, u8 *, u32 *, u32); +extern u32 hdlc_decode(u8 *, u8 *, u32); + +/* Function prototypes from tpam_crcpc.c */ +extern void init_CRC(void); +extern void hdlc_encode_modem(u8 *, u32, u8 *, u32 *); +extern void hdlc_no_accm_encode(u8 *, u32, u8 *, u32 *); +extern u32 hdlc_no_accm_decode(u8 *, u32); + +/* Define this to enable debug tracing prints */ +#undef DEBUG + +#ifdef DEBUG +#define dprintk printk +#else +#define dprintk while(0) printk +#endif + +#endif /* _TPAM_H_ */ diff --git a/drivers/isdn/tpam/tpam_commands.c b/drivers/isdn/tpam/tpam_commands.c new file mode 100644 index 000000000000..43a1d37b6936 --- /dev/null +++ b/drivers/isdn/tpam/tpam_commands.c @@ -0,0 +1,1035 @@ +/* $Id: tpam_commands.c,v 1.1.2.2 2001/06/08 08:23:46 kai Exp $ + * + * Turbo PAM ISDN driver for Linux. (Kernel Driver - ISDN commands) + * + * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * For all support questions please contact: <support@auvertech.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/tqueue.h> +#include <linux/interrupt.h> +#include <asm/io.h> + +#include <linux/isdn/tpam.h> +#include "tpam.h" + +/* Local functions prototypes */ +static int tpam_command_ioctl_dspload(tpam_card *, u32); +static int tpam_command_ioctl_dspsave(tpam_card *, u32); +static int tpam_command_ioctl_dsprun(tpam_card *); +static int tpam_command_ioctl_loopmode(tpam_card *, u8); +static int tpam_command_dial(tpam_card *, u32, u8 *); +static int tpam_command_setl2(tpam_card *, u32, u8); +static int tpam_command_getl2(tpam_card *, u32); +static int tpam_command_acceptd(tpam_card *, u32); +static int tpam_command_acceptb(tpam_card *, u32); +static int tpam_command_hangup(tpam_card *, u32); +static int tpam_command_proceed(tpam_card *, u32); +static void tpam_statcallb_run(unsigned long); +static void tpam_statcallb(tpam_card *, isdn_ctrl); + +/* + * Function called when the ISDN link level send a command to the driver. + * + * c: ISDN command. + * + * Return: 0 if OK, <0 on errors. + */ +int tpam_command(isdn_ctrl *c) { + tpam_card *card; + unsigned long argp; + + dprintk("TurboPAM(tpam_command) card=%d, command=%d\n", + c->driver, c->command); + + /* search for the board */ + if (!(card = tpam_findcard(c->driver))) { + printk(KERN_ERR "TurboPAM(tpam_command): invalid driverId %d\n", + c->driver); + return -ENODEV; + } + + /* dispatch the command */ + switch (c->command) { + case ISDN_CMD_IOCTL: + argp = c->parm.userdata; + switch (c->arg) { + case TPAM_CMD_DSPLOAD: + return tpam_command_ioctl_dspload(card, + argp); + case TPAM_CMD_DSPSAVE: + return tpam_command_ioctl_dspsave(card, + argp); + case TPAM_CMD_DSPRUN: + return tpam_command_ioctl_dsprun(card); + case TPAM_CMD_LOOPMODEON: + return tpam_command_ioctl_loopmode(card, + 1); + case TPAM_CMD_LOOPMODEOFF: + return tpam_command_ioctl_loopmode(card, + 0); + default: + dprintk("TurboPAM(tpam_command): " + "invalid tpam ioctl %ld\n", + c->arg); + return -EINVAL; + } + case ISDN_CMD_DIAL: + return tpam_command_dial(card, c->arg, + c->parm.setup.phone); + case ISDN_CMD_ACCEPTD: + return tpam_command_acceptd(card, c->arg); + case ISDN_CMD_ACCEPTB: + return tpam_command_acceptb(card, c->arg); + case ISDN_CMD_HANGUP: + return tpam_command_hangup(card, c->arg); + case ISDN_CMD_SETL2: + return tpam_command_setl2(card, c->arg & 0xff, + c->arg >> 8); + case ISDN_CMD_GETL2: + return tpam_command_getl2(card, c->arg); + case ISDN_CMD_LOCK: + MOD_INC_USE_COUNT; + return 0; + case ISDN_CMD_UNLOCK: + MOD_DEC_USE_COUNT; + return 0; + case ISDN_CMD_PROCEED: + return tpam_command_proceed(card, c->arg); + default: + dprintk("TurboPAM(tpam_command): " + "unknown or unused isdn ioctl %d\n", + c->command); + return -EINVAL; + } + + /* not reached */ + return -EINVAL; +} + +/* + * Load some data into the board's memory. + * + * card: the board + * arg: IOCTL argument containing the user space address of + * the tpam_dsp_ioctl structure describing the IOCTL. + * + * Return: 0 if OK, <0 on errors. + */ +static int tpam_command_ioctl_dspload(tpam_card *card, u32 arg) { + tpam_dsp_ioctl tdl; + int ret; + + dprintk("TurboPAM(tpam_command_ioctl_dspload): card=%d\n", card->id); + + /* get the IOCTL parameter from userspace */ + if (copy_from_user(&tdl, (void *)arg, sizeof(tpam_dsp_ioctl))) + return -EFAULT; + + /* if the board's firmware was started, protect against writes + * to unallowed memory areas. If the board's firmware wasn't started, + * all is allowed. */ + if (card->running && tpam_verify_area(tdl.address, tdl.data_len)) + return -EPERM; + + /* write the data in the board's memory */ + ret = copy_from_user_to_pam(card, (void *)tdl.address, + (void *)arg + sizeof(tpam_dsp_ioctl), + tdl.data_len); + return 0; +} + +/* + * Extract some data from the board's memory. + * + * card: the board + * arg: IOCTL argument containing the user space address of + * the tpam_dsp_ioctl structure describing the IOCTL. + * + * Return: 0 if OK, <0 on errors. + */ +static int tpam_command_ioctl_dspsave(tpam_card *card, u32 arg) { + tpam_dsp_ioctl tdl; + int ret; + + dprintk("TurboPAM(tpam_command_ioctl_dspsave): card=%d\n", card->id); + + /* get the IOCTL parameter from userspace */ + if (copy_from_user(&tdl, (void *)arg, sizeof(tpam_dsp_ioctl))) + return -EFAULT; + + /* protect against read from unallowed memory areas */ + if (tpam_verify_area(tdl.address, tdl.data_len)) + return -EPERM; + + /* read the data from the board's memory */ + ret = copy_from_pam_to_user(card, (void *)arg + sizeof(tpam_dsp_ioctl), + (void *)tdl.address, tdl.data_len); + return ret; +} + +/* + * Launch the board's firmware. This function must be called after the + * firmware was loaded into the board's memory using TPAM_CMD_DSPLOAD + * IOCTL commands. After launching the firmware, this function creates + * the NCOs and waits for their creation. + * + * card: the board + * + * Return: 0 if OK, <0 on errors. + */ +static int tpam_command_ioctl_dsprun(tpam_card *card) { + u32 signature = 0, timeout, i; + isdn_ctrl ctrl; + struct sk_buff *skb; + + dprintk("TurboPAM(tpam_command_ioctl_dsprun): card=%d\n", card->id); + + /* board must _not_ be running */ + if (card->running) + return -EBUSY; + + /* reset the board */ + spin_lock_irq(&card->lock); + copy_to_pam_dword(card, (void *)TPAM_MAGICNUMBER_REGISTER, 0xdeadface); + readl(card->bar0 + TPAM_DSPINT_REGISTER); + readl(card->bar0 + TPAM_HINTACK_REGISTER); + spin_unlock_irq(&card->lock); + + /* wait for the board signature */ + timeout = jiffies + SIGNATURE_TIMEOUT; + while (timeout > jiffies) { + spin_lock_irq(&card->lock); + signature = copy_from_pam_dword(card, + (void *)TPAM_MAGICNUMBER_REGISTER); + spin_unlock_irq(&card->lock); + if (signature == TPAM_MAGICNUMBER) + break; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(2); + } + + /* signature not present -> board not started */ + if (signature != TPAM_MAGICNUMBER) { + printk(KERN_ERR "TurboPAM(tpam_command_ioctl_dsprun): " + "card=%d, signature 0x%lx, expected 0x%lx\n", + card->id, (unsigned long)signature, + (unsigned long)TPAM_MAGICNUMBER); + printk(KERN_ERR "TurboPAM(tpam_command_ioctl_dsprun): " + "card=%d, firmware not started\n", card->id); + return -EIO; + } + + /* the firmware is started */ + printk(KERN_INFO "TurboPAM: card=%d, firmware started\n", card->id); + + /* init the CRC routines */ + init_CRC(); + + /* create all the NCOs */ + for (i = 0; i < TPAM_NBCHANNEL; ++i) + if ((skb = build_ACreateNCOReq(""))) + tpam_enqueue(card, skb); + + /* wait for NCO creation confirmation */ + timeout = jiffies + NCOCREATE_TIMEOUT; + while (timeout > jiffies) { + if (card->channels_tested == TPAM_NBCHANNEL) + break; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(2); + } + + card->running = 1; + + if (card->channels_tested != TPAM_NBCHANNEL) + printk(KERN_ERR "TurboPAM(tpam_command_ioctl_dsprun): " + "card=%d, tried to init %d channels, " + "got reply from only %d channels\n", card->id, + TPAM_NBCHANNEL, card->channels_tested); + + /* if all the channels were not initialized, signal to the ISDN + * link layer that fact that some channels are not usable */ + if (card->channels_used != TPAM_NBCHANNEL) + for (i = card->channels_used; i < TPAM_NBCHANNEL; ++i) { + ctrl.driver = card->id; + ctrl.command = ISDN_STAT_DISCH; + ctrl.arg = i; + ctrl.parm.num[0] = 0; + (* card->interface.statcallb)(&ctrl); + } + + printk(KERN_INFO "TurboPAM: card=%d, ready, %d channels available\n", + card->id, card->channels_used); + + /* let's rock ! */ + ctrl.driver = card->id; + ctrl.command = ISDN_STAT_RUN; + ctrl.arg = 0; + tpam_statcallb(card, ctrl); + + return 0; +} + +/* + * Set/reset the board's looptest mode. + * + * card: the board + * mode: if 1, sets the board's looptest mode, if 0 resets it. + * + * Return: 0 if OK, <0 if error. + */ +static int tpam_command_ioctl_loopmode(tpam_card *card, u8 mode) { + + /* board must be running */ + if (!card->running) + return -ENODEV; + + card->loopmode = mode; + return 0; +} + +/* + * Issue a dial command. This function builds and sends a CConnectReq. + * + * card: the board + * channel: the channel number + * phone: the remote phone number (EAZ) + * + * Return: 0 if OK, <0 if error. + */ +static int tpam_command_dial(tpam_card *card, u32 channel, u8 *phone) { + struct sk_buff *skb; + isdn_ctrl ctrl; + + dprintk("TurboPAM(tpam_command_dial): card=%d, channel=%lu, phone=%s\n", + card->id, (unsigned long)channel, phone); + + /* board must be running */ + if (!card->running) + return -ENODEV; + + /* initialize channel parameters */ + card->channels[channel].realhdlc = card->channels[channel].hdlc; + card->channels[channel].hdlcshift = 0; + card->channels[channel].readytoreceive = 0; + + /* build and send a CConnectReq */ + skb = build_CConnectReq(card->channels[channel].ncoid, phone, + card->channels[channel].realhdlc); + if (!skb) + return -ENOMEM; + tpam_enqueue(card, skb); + + /* making a connection in modem mode is slow and causes the ISDN + * link layer to hangup the connection before even it gets a chance + * to establish... All we can do is simulate a successful connection + * for now, and send a DHUP later if the connection fails */ + if (!card->channels[channel].realhdlc) { + ctrl.driver = card->id; + ctrl.command = ISDN_STAT_DCONN; + ctrl.arg = channel; + tpam_statcallb(card, ctrl); + } + + return 0; +} + +/* + * Set the level2 protocol (modem or HDLC). + * + * card: the board + * channel: the channel number + * proto: the level2 protocol (one of ISDN_PROTO_L2*) + * + * Return: 0 if OK, <0 if error. + */ +static int tpam_command_setl2(tpam_card *card, u32 channel, u8 proto) { + + dprintk("TurboPAM(tpam_command_setl2): card=%d, channel=%lu, proto=%d\n", + card->id, (unsigned long)channel, proto); + + /* board must be running */ + if (!card->running) + return -ENODEV; + + /* set the hdlc/modem mode */ + switch (proto) { + case ISDN_PROTO_L2_HDLC: + card->channels[channel].hdlc = 1; + break; + case ISDN_PROTO_L2_MODEM: + card->channels[channel].hdlc = 0; + break; + default: + return -EINVAL; + } + return 0; +} + +/* + * Return the level2 protocol (modem or HDLC). + * + * card: the board + * channel: the channel number + * + * Return: ISDN_PROTO_L2_HDLC/MODEM if OK, <0 if error. + */ +static int tpam_command_getl2(tpam_card *card, u32 channel) { + + dprintk("TurboPAM(tpam_command_getl2): card=%d, channel=%lu\n", + card->id, (unsigned long)channel); + + /* board must be running */ + if (!card->running) + return -ENODEV; + + /* return the current mode */ + if (card->channels[channel].realhdlc) + return ISDN_PROTO_L2_HDLC; + else + return ISDN_PROTO_L2_MODEM; +} + +/* + * Accept a D-channel connection (incoming connection). This function + * builds and sends a CConnectRsp message and signals DCONN to the ISDN + * link level. + * + * card: the board + * channel: the channel number + * + * Return: 0 if OK, <0 if error. + */ +static int tpam_command_acceptd(tpam_card *card, u32 channel) { + isdn_ctrl ctrl; + struct sk_buff *skb; + + dprintk("TurboPAM(tpam_command_acceptd): card=%d, channel=%lu\n", + card->id, (unsigned long)channel); + + /* board must be running */ + if (!card->running) + return -ENODEV; + + /* build and send a CConnectRsp */ + skb = build_CConnectRsp(card->channels[channel].ncoid); + if (!skb) + return -ENOMEM; + tpam_enqueue(card, skb); + + /* issue DCONN to the ISDN link level */ + ctrl.driver = card->id; + ctrl.command = ISDN_STAT_DCONN; + ctrl.arg = channel; + tpam_statcallb(card, ctrl); + return 0; +} + +/* + * Accepts a B-channel connection. This is not used by the driver, + * since the TurboPAM is an active card hiding its B-channels from + * us. We just signal BCONN to the ISDN link layer. + * + * card: the board + * channel: the channel number + * + * Return: 0 if OK, <0 if error. + */ +static int tpam_command_acceptb(tpam_card *card, u32 channel) { + isdn_ctrl ctrl; + + dprintk("TurboPAM(tpam_command_acceptb): card=%d, channel=%lu\n", + card->id, (unsigned long)channel); + + /* board must be running */ + if (!card->running) + return -ENODEV; + + /* issue BCONN to the ISDN link level */ + ctrl.driver = card->id; + ctrl.command = ISDN_STAT_BCONN; + ctrl.arg = channel; + ctrl.parm.num[0] = '\0'; + tpam_statcallb(card, ctrl); + return 0; +} + +/* + * Hang up a connection. This function builds and sends a CDisconnectReq. + * + * card: the board + * channel: the channel number. + * + * Return: 0 if OK, <0 if error. + */ +static int tpam_command_hangup(tpam_card *card, u32 channel) { + struct sk_buff *skb; + + dprintk("TurboPAM(tpam_command_hangup): card=%d, channel=%lu\n", + card->id, (unsigned long)channel); + + /* board must be running */ + if (!card->running) + return -ENODEV; + + /* build and send a CDisconnectReq */ + skb = build_CDisconnectReq(card->channels[channel].ncoid); + if (!skb) + return -ENOMEM; + tpam_enqueue(card, skb); + return 0; +} + +/* + * Proceed with an incoming connection. This function builds and sends a + * CConnectRsp. + * + * card: the board + * channel: the channel number. + * + * Return: 0 if OK, <0 if error. + */ +static int tpam_command_proceed(tpam_card *card, u32 channel) { + struct sk_buff *skb; + + dprintk("TurboPAM(tpam_command_proceed): card=%d, channel=%lu\n", + card->id, (unsigned long)channel); + + /* board must be running */ + if (!card->running) + return -ENODEV; + + /* build and send a CConnectRsp */ + skb = build_CConnectRsp(card->channels[channel].ncoid); + if (!skb) + return -ENOMEM; + tpam_enqueue(card, skb); + return 0; +} + +/* + * Send data through the board. This function encodes the data depending + * on the connection type (modem or HDLC), then builds and sends a U3DataReq. + * + * driverId: the driver id (really meaning here the board) + * channel: the channel number + * ack: data needs to be acknowledged upon send + * skb: sk_buff containing the data + * + * Return: size of data send if OK, <0 if error. + */ +int tpam_writebuf_skb(int driverId, int channel, int ack, struct sk_buff *skb) { + tpam_card *card; + int orig_size = skb->len; + void *finaldata; + u32 finallen; + + dprintk("TurboPAM(tpam_writebuf_skb): " + "card=%d, channel=%ld, ack=%d, data size=%d\n", + driverId, (unsigned long)channel, ack, skb->len); + + /* find the board based on its driver ID */ + if (!(card = tpam_findcard(driverId))) { + printk(KERN_ERR "TurboPAM(tpam_writebuf_skb): " + "invalid driverId %d\n", driverId); + return -ENODEV; + } + + /* board must be running */ + if (!card->running) + return -ENODEV; + + /* allocate some temporary memory */ + if (!(finaldata = (void *)__get_free_page(GFP_ATOMIC))) { + printk(KERN_ERR "TurboPAM(tpam_writebuf_skb): " + "get_free_page failed\n"); + return -ENOMEM; + } + + /* encode the data */ + if (!card->channels[channel].realhdlc) { + /* modem mode */ + hdlc_encode_modem(skb->data, skb->len, finaldata, &finallen); + } + else { + /* HDLC mode */ + void *tempdata; + u32 templen; + + if (!(tempdata = (void *)__get_free_page(GFP_ATOMIC))) { + printk(KERN_ERR "TurboPAM(tpam_writebuf_skb): " + "get_free_page failed\n"); + free_page((u32)finaldata); + return -ENOMEM; + } + hdlc_no_accm_encode(skb->data, skb->len, tempdata, &templen); + finallen = hdlc_encode(tempdata, finaldata, + &card->channels[channel].hdlcshift, + templen); + free_page((u32)tempdata); + } + + /* free the old sk_buff */ + kfree_skb(skb); + + /* build and send a U3DataReq */ + skb = build_U3DataReq(card->channels[channel].ncoid, finaldata, + finallen, ack, orig_size); + if (!skb) { + free_page((u32)finaldata); + return -ENOMEM; + } + tpam_enqueue_data(&card->channels[channel], skb); + + /* free the temporary memory */ + free_page((u32)finaldata); + return orig_size; +} + +/* + * Treat a received ACreateNCOCnf message. + * + * card: the board + * skb: the received message + */ +void tpam_recv_ACreateNCOCnf(tpam_card *card, struct sk_buff *skb) { + u32 ncoid; + u8 status; + u32 channel; + + dprintk("TurboPAM(tpam_recv_ACreateNCOCnf): card=%d\n", card->id); + + /* parse the message contents */ + if (parse_ACreateNCOCnf(skb, &status, &ncoid)) + return; + + /* if the card is alreay running, it means that this message + * arrives too late... */ + if (card->running) { + printk(KERN_ERR "TurboPAM(tpam_recv_ACreateNCOCnf): " + "ACreateNCOCnf received too late, status=%d\n", status); + return; + } + + /* the NCO creation failed, the corresponding channel will + * be unused */ + if (status) { + printk(KERN_ERR "TurboPAM(tpam_recv_ACreateNCOCnf): " + "ACreateNCO failed, status=%d\n", status); + card->channels_tested++; + return; + } + + /* find the first free channel and assign the nco ID to it */ + if ((channel = tpam_findchannel(card, TPAM_NCOID_INVALID)) == TPAM_CHANNEL_INVALID) { + printk(KERN_ERR "TurboPAM(tpam_recv_ACreateNCOCnf): " + "All channels are assigned\n"); + return; + } + card->channels[channel].ncoid = ncoid; + card->channels_tested++; + card->channels_used++; +} + +/* + * Treat a received ADestroyNCOCnf message. Not used by the driver. + * + * card: the board + * skb: the received message + */ +void tpam_recv_ADestroyNCOCnf(tpam_card *card, struct sk_buff *skb) { + u32 ncoid; + u8 status; + u32 channel; + + dprintk("TurboPAM(tpam_recv_ADestroyNCOCnf): card=%d\n", card->id); + + /* parse the message contents */ + if (parse_ADestroyNCOCnf(skb, &status, &ncoid)) + return; + + if (status) { + printk(KERN_ERR "TurboPAM(tpam_recv_ADestroyNCOCnf): " + "ADestroyNCO failed, status=%d\n", status); + return; + } + + /* clears the channel's nco ID */ + if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) { + printk(KERN_ERR "TurboPAM(tpam_recv_ADestroyNCOCnf): " + "ncoid invalid %lu\n", (unsigned long)ncoid); + return; + } + + card->channels[channel].ncoid = TPAM_NCOID_INVALID; +} + +/* + * Treat a received CConnectCnf message. + * + * card: the board + * skb: the received message + */ +void tpam_recv_CConnectCnf(tpam_card *card, struct sk_buff *skb) { + u32 ncoid; + u32 channel; + isdn_ctrl ctrl; + + dprintk("TurboPAM(tpam_recv_CConnectCnf): card=%d\n", card->id); + + /* parse the message contents */ + if (parse_CConnectCnf(skb, &ncoid)) + return; + + /* find the channel by its nco ID */ + if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) { + printk(KERN_ERR "TurboPAM(tpam_recv_CConnectCnf): " + "ncoid invalid %lu\n", (unsigned long)ncoid); + return; + } + + /* issue a DCONN command to the ISDN link layer if we are in HDLC mode. + * In modem mode, we alreay did it - the ISDN timer kludge */ + if (card->channels[channel].realhdlc) { + ctrl.driver = card->id; + ctrl.command = ISDN_STAT_DCONN; + ctrl.arg = channel; + (* card->interface.statcallb)(&ctrl); + } +} + +/* + * Treat a received CConnectInd message. This function signals a ICALL + * to the ISDN link layer. + * + * card: the board + * skb: the received message + */ +void tpam_recv_CConnectInd(tpam_card *card, struct sk_buff *skb) { + u32 ncoid; + u32 channel; + u8 hdlc, plan, screen; + u8 calling[PHONE_MAXIMUMSIZE], called[PHONE_MAXIMUMSIZE]; + isdn_ctrl ctrl; + int status; + + dprintk("TurboPAM(tpam_recv_CConnectInd): card=%d\n", card->id); + + /* parse the message contents */ + if (parse_CConnectInd(skb, &ncoid, &hdlc, calling, called, &plan, &screen)) + return; + + /* find the channel by its nco ID */ + if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) { + printk(KERN_ERR "TurboPAM(tpam_recv_CConnectInd): " + "ncoid invalid %lu\n", (unsigned long)ncoid); + return; + } + + /* initialize the channel parameters */ + card->channels[channel].realhdlc = hdlc; + card->channels[channel].hdlcshift = 0; + card->channels[channel].readytoreceive = 0; + + /* issue a ICALL command to the ISDN link layer */ + ctrl.driver = card->id; + ctrl.command = ISDN_STAT_ICALL; + ctrl.arg = channel; + memcpy(ctrl.parm.setup.phone, calling, 32); + memcpy(ctrl.parm.setup.eazmsn, called, 32); + ctrl.parm.setup.si1 = 7; /* data capability */ + ctrl.parm.setup.si2 = 0; + ctrl.parm.setup.plan = plan; + ctrl.parm.setup.screen = screen; + + status = (* card->interface.statcallb)(&ctrl); + switch (status) { + case 1: + case 4: + /* call accepted, link layer will send us a ACCEPTD + * command later */ + dprintk("TurboPAM(tpam_recv_CConnectInd): " + "card=%d, channel=%d, icall waiting, status=%d\n", + card->id, channel, status); + break; + default: + /* call denied, we build and send a CDisconnectReq */ + dprintk("TurboPAM(tpam_recv_CConnectInd): " + "card=%d, channel=%d, icall denied, status=%d\n", + card->id, channel, status); + skb = build_CDisconnectReq(ncoid); + if (!skb) + return; + tpam_enqueue(card, skb); + } +} + +/* + * Treat a received CDisconnectInd message. This function signals a DHUP and + * a BHUP to the ISDN link layer. + * + * card: the board + * skb: the received message + */ +void tpam_recv_CDisconnectInd(tpam_card *card, struct sk_buff *skb) { + u32 ncoid; + u32 channel; + u32 cause; + isdn_ctrl ctrl; + + dprintk("TurboPAM(tpam_recv_CDisconnectInd): card=%d\n", card->id); + + /* parse the message contents */ + if (parse_CDisconnectInd(skb, &ncoid, &cause)) + return; + + /* find the channel by its nco ID */ + if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) { + printk(KERN_ERR "TurboPAM(tpam_recv_CDisconnectInd): " + "ncoid invalid %lu\n", (unsigned long)ncoid); + return; + } + + /* build and send a CDisconnectRsp */ + skb = build_CDisconnectRsp(ncoid); + if (!skb) + return; + tpam_enqueue(card, skb); + + /* issue a DHUP to the ISDN link layer */ + ctrl.driver = card->id; + ctrl.command = ISDN_STAT_DHUP; + ctrl.arg = channel; + (* card->interface.statcallb)(&ctrl); + + /* issue a BHUP to the ISDN link layer */ + ctrl.driver = card->id; + ctrl.command = ISDN_STAT_BHUP; + ctrl.arg = channel; + (* card->interface.statcallb)(&ctrl); +} + +/* + * Treat a received CDisconnectCnf message. This function signals a DHUP and + * a BHUP to the ISDN link layer. + * + * card: the board + * skb: the received message + */ +void tpam_recv_CDisconnectCnf(tpam_card *card, struct sk_buff *skb) { + u32 ncoid; + u32 channel; + u32 cause; + isdn_ctrl ctrl; + + dprintk("TurboPAM(tpam_recv_CDisconnectCnf): card=%d\n", card->id); + + /* parse the message contents */ + if (parse_CDisconnectCnf(skb, &ncoid, &cause)) + return; + + /* find the channel by its nco ID */ + if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) { + printk(KERN_ERR "TurboPAM(tpam_recv_CDisconnectCnf): " + "ncoid invalid %lu\n", (unsigned long)ncoid); + return; + } + + /* issue a DHUP to the ISDN link layer */ + ctrl.driver = card->id; + ctrl.command = ISDN_STAT_DHUP; + ctrl.arg = channel; + (* card->interface.statcallb)(&ctrl); + + /* issue a BHUP to the ISDN link layer */ + ctrl.driver = card->id; + ctrl.command = ISDN_STAT_BHUP; + ctrl.arg = channel; + (* card->interface.statcallb)(&ctrl); +} + +/* + * Treat a received U3DataInd message. This function decodes the data + * depending on the connection type (modem or HDLC) and passes it to the + * ISDN link layer by using rcvcallb_skb. + * + * card: the board + * skb: the received message + data + */ +void tpam_recv_U3DataInd(tpam_card *card, struct sk_buff *skb) { + u32 ncoid; + u32 channel; + u8 *data; + u16 len; + struct sk_buff *result; + + dprintk("TurboPAM(tpam_recv_U3DataInd): card=%d, datalen=%d\n", + card->id, skb->len); + + /* parse the message contents */ + if (parse_U3DataInd(skb, &ncoid, &data, &len)) + return; + + /* find the channel by its nco ID */ + if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) { + printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): " + "ncoid invalid %lu\n", (unsigned long)ncoid); + return; + } + + /* decode the data */ + if (card->channels[ncoid].realhdlc) { + /* HDLC mode */ + u8 *tempdata; + u32 templen; + + if (!(tempdata = (void *)__get_free_page(GFP_ATOMIC))) { + printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): " + "get_free_page failed\n"); + return; + } + templen = hdlc_decode(data, tempdata, len); + templen = hdlc_no_accm_decode(tempdata, templen); + if (!(result = alloc_skb(templen, GFP_ATOMIC))) { + printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): " + "alloc_skb failed\n"); + free_page((u32)tempdata); + return; + } + memcpy(skb_put(result, templen), tempdata, templen); + free_page((u32)tempdata); + } + else { + /* modem mode */ + if (!(result = alloc_skb(len, GFP_ATOMIC))) { + printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): " + "alloc_skb failed\n"); + return; + } + memcpy(skb_put(result, len), data, len); + } + + /* In loop mode, resend the data immediatly */ + if (card->loopmode) { + struct sk_buff *loopskb; + + if (!(loopskb = alloc_skb(skb->len, GFP_ATOMIC))) { + printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): " + "alloc_skb failed\n"); + kfree_skb(result); + return; + } + memcpy(skb_put(loopskb, result->len), result->data, + result->len); + if (tpam_writebuf_skb(card->id, channel, 0, loopskb) < 0) + kfree_skb(loopskb); + } + + /* pass the data to the ISDN link layer */ + (* card->interface.rcvcallb_skb)(card->id, channel, result); +} + +/* + * Treat a received U3ReadyToReceiveInd message. This function sets the + * channel ready flag and triggers the send of data if the channel becomed + * ready. + * + * card: the board + * skb: the received message + data + */ +void tpam_recv_U3ReadyToReceiveInd(tpam_card *card, struct sk_buff *skb) { + u32 ncoid; + u32 channel; + u8 ready; + + dprintk("TurboPAM(tpam_recv_U3ReadyToReceiveInd): card=%d\n", card->id); + + /* parse the message contents */ + if (parse_U3ReadyToReceiveInd(skb, &ncoid, &ready)) + return; + + /* find the channel by its nco ID */ + if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) { + printk(KERN_ERR "TurboPAM(tpam_recv_U3ReadyToReceiveInd): " + "ncoid invalid %lu\n", (unsigned long)ncoid); + return; + } + + /* set the readytoreceive flag */ + card->channels[channel].readytoreceive = ready; + + /* if the channel just becomed ready, trigger the send of queued data */ + if (ready) + tpam_enqueue_data(&card->channels[channel], NULL); +} + +/* + * Runs the delayed statcallb when its timer expires. + * + * parm: pointer to the tpam_statcallb_data statcallb argument. + */ +static void tpam_statcallb_run(unsigned long parm) { + tpam_statcallb_data *ds = (tpam_statcallb_data *)parm; + + dprintk("TurboPAM(tpam_statcallb_run)\n"); + + (* ds->card->interface.statcallb)(&ds->ctrl); + + kfree(ds->timer); + kfree(ds); +} + +/* + * Queues a statcallb call for delayed invocation. + * + * card: the board + * ctrl: the statcallb argument + */ +static void tpam_statcallb(tpam_card *card, isdn_ctrl ctrl) { + struct timer_list *timer; + tpam_statcallb_data *ds; + + dprintk("TurboPAM(tpam_statcallb): card=%d\n", card->id); + + if (!(timer = (struct timer_list *) kmalloc(sizeof(struct timer_list), + GFP_ATOMIC))) { + printk(KERN_ERR "TurboPAM: tpam_statcallb: kmalloc failed!\n"); + return; + } + + if (!(ds = (tpam_statcallb_data *) kmalloc(sizeof(tpam_statcallb_data), + GFP_ATOMIC))) { + printk(KERN_ERR "TurboPAM: tpam_statcallb: kmalloc failed!\n"); + kfree(timer); + return; + } + ds->card = card; + ds->timer = timer; + memcpy(&ds->ctrl, &ctrl, sizeof(isdn_ctrl)); + + init_timer(timer); + timer->function = tpam_statcallb_run; + timer->data = (unsigned long)ds; + timer->expires = jiffies + 0.1 * HZ; /* 0.1 second */ + add_timer(timer); +} diff --git a/drivers/isdn/tpam/tpam_crcpc.c b/drivers/isdn/tpam/tpam_crcpc.c new file mode 100644 index 000000000000..f2dcf2daf3b9 --- /dev/null +++ b/drivers/isdn/tpam/tpam_crcpc.c @@ -0,0 +1,207 @@ +/* $Id: tpam_crcpc.c,v 1.1.2.1 2001/06/05 19:45:37 kai Exp $ + * + * Turbo PAM ISDN driver for Linux. (Kernel Driver - CRC encoding) + * + * Copyright 1998-2000 AUVERTECH Télécom + * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * For all support questions please contact: <support@auvertech.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Module Name: + + crcpc.c + +Abstract: + + Modem HDLC coding + Software HDLC coding / decoding + +Revision History: + +---------------------------------------------------------------------------*/ + +#include "tpam.h" + +#define HDLC_CTRL_CHAR_CMPL_MASK 0x20 /* HDLC control character complement mask */ +#define HDLC_FLAG 0x7E /* HDLC flag */ +#define HDLC_CTRL_ESC 0x7D /* HDLC control escapr character */ +#define HDLC_LIKE_FCS_INIT_VAL 0xFFFF /* FCS initial value (0xFFFF for new equipment or 0) */ +#define HDLC_FCS_OK 0xF0B8 /* This value is the only valid value of FCS */ + +#define TRUE 1 +#define FALSE 0 + +static u16 t_ap_hdlc_like_fcs [256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +static u8 ap_t_ctrl_char_complemented[256]; /* list of characters to complement */ + +static void ap_hdlc_like_ctrl_char_list (u32 ctrl_char) { + int i; + + for (i = 0; i < 256; ++i) + ap_t_ctrl_char_complemented[i] = FALSE; + for (i = 0; i < 32; ++i) + if ((ctrl_char >> i) & 0x0001) + ap_t_ctrl_char_complemented [i] = TRUE; + ap_t_ctrl_char_complemented[HDLC_FLAG] = TRUE; + ap_t_ctrl_char_complemented[HDLC_CTRL_ESC] = TRUE; + +} + +void init_CRC() { + ap_hdlc_like_ctrl_char_list(0xffffffff); +} + +void hdlc_encode_modem(u8 *buffer_in, u32 lng_in, + u8 *buffer_out, u32 *lng_out) { + u16 fcs; + register u8 data; + register u8 *p_data_out = buffer_out; + + fcs = HDLC_LIKE_FCS_INIT_VAL; + + /* + * Insert HDLC flag at the beginning of the frame + */ + *p_data_out++ = HDLC_FLAG; + +#define ESCAPE_CHAR(data_out, data) \ + if (ap_t_ctrl_char_complemented[data]) { \ + *data_out++ = HDLC_CTRL_ESC; \ + *data_out++ = data ^ 0x20; \ + } \ + else \ + *data_out++ = data; + + while (lng_in--) { + data = *buffer_in++; + + /* + * FCS calculation + */ + fcs = (fcs>>8) ^ t_ap_hdlc_like_fcs[((u8)(fcs^data)) & 0xff]; + + ESCAPE_CHAR(p_data_out, data); + } + + /* + * Add FCS and closing flag + */ + fcs ^= 0xFFFF; // Complement + + data = (u8)(fcs & 0xff); /* LSB */ + ESCAPE_CHAR(p_data_out, data); + + data = (u8)((fcs >> 8)); /* MSB */ + ESCAPE_CHAR(p_data_out, data); +#undef ESCAPE_CHAR + + *p_data_out++ = HDLC_FLAG; + + *lng_out = (u32)(p_data_out - buffer_out); +} + +void hdlc_no_accm_encode(u8 *buffer_in, u32 lng_in, + u8 *buffer_out, u32 *lng_out) { + u16 fcs; + register u8 data; + register u8 *p_data_out = buffer_out; + + /* + * Insert HDLC flag at the beginning of the frame + */ + fcs = HDLC_LIKE_FCS_INIT_VAL; + + while (lng_in--) { + data = *buffer_in++; + /* calculate FCS */ + fcs = (fcs>>8) ^ t_ap_hdlc_like_fcs[((u8)(fcs^data)) & 0xff]; + *p_data_out++ = data; + } + + /* + * Add FCS and closing flag + */ + fcs ^= 0xFFFF; // Complement + data = (u8)(fcs); + *p_data_out++ = data; + + data =(u8)((fcs >> 8)); // revense MSB / LSB + *p_data_out++ = data; + + *lng_out = (u32)(p_data_out - buffer_out); +} + +u32 hdlc_no_accm_decode(u8 *buffer_in, u32 lng_in) { + u16 fcs; + u32 lng = lng_in; + register u8 data; + + /* + * Insert HDLC flag at the beginning of the frame + */ + fcs = HDLC_LIKE_FCS_INIT_VAL; + + while (lng_in--) { + data = *buffer_in++; + /* calculate FCS */ + fcs = (fcs>>8) ^ t_ap_hdlc_like_fcs[((u8)(fcs^data)) & 0xff]; + } + + if (fcs == HDLC_FCS_OK) + return (lng-2); + else + return 0; +} + diff --git a/drivers/isdn/tpam/tpam_hdlc.c b/drivers/isdn/tpam/tpam_hdlc.c new file mode 100644 index 000000000000..0337535d7915 --- /dev/null +++ b/drivers/isdn/tpam/tpam_hdlc.c @@ -0,0 +1,934 @@ +/* $Id: tpam_hdlc.c,v 1.1.2.1 2001/06/05 19:45:37 kai Exp $ + * + * Turbo PAM ISDN driver for Linux. (Kernel Driver - HDLC encoding) + * + * Copyright 1998-2000 AUVERTECH Télécom + * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * For all support questions please contact: <support@auvertech.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Module Name: + + hdlc.c + +Abstract: + + stuff0 : array necessary for the bit stuffing algorithm + stuff1 : array necessary for the bit stuffing algorithm + stuff2 : array necessary for the bit stuffing algorithm + stuff3 : array necessary for the bit stuffing algorithm + stuff4 : array necessary for the bit stuffing algorithm + stuff5 : array necessary for the bit stuffing algorithm + stuffs[] : array conaining the previous 6 arrays + destuff0 : array necessary for the bit destuffing algorithm + destuff1 : array necessary for the bit destuffing algorithm + destuff2 : array necessary for the bit destuffing algorithm + destuff3 : array necessary for the bit destuffing algorithm + destuff4 : array necessary for the bit destuffing algorithm + destuff5 : array necessary for the bit destuffing algorithm + destuffs[] : array conaining the previous 6 arrays + + hdlc_encode : bit stuffing of a byte array, with the addition of a start and + end flag, using the bit shift given in parameter (which is + updated at the end of encoding). + hdlc_decode : bit de-stuffing of a byte array with detection of possible + ABORTs. + +Revision History: + +---------------------------------------------------------------------------*/ + +/* The arrays are used as follows: + + For the bit stuffing : + + stuff0 = used if the previous byte ended with '0' + stuff1 = used if the previous byte ended with '10' + stuff2 = used if the previous byte ended with '110' + stuff3 = used if the previous byte ended with '1110' + stuff4 = used if the previous byte ended with '11110' + stuff5 = used if the previous byte ended with '111110' + + those arrays are indexed by the byte to stuff. + + the data of those arrays are of the form (in binary): + "bbbbaaaa cccccccc" + with "cccccccc" : byte stuffed + "aaaa" : "0000" --> no insertion of '0' + "0100" --> 1 '0' inserted, carry = '0' + "0101" --> 1 '0' inserted, carry = '1' + "1000" --> 2 '0' inserted, carry = '00' + "1001" --> 2 '0' inserted, carry = '01' + "1010" --> 2 '0' inserted, carry = '10' + "1011" --> 2 '0' inserted, carry = '11' + "bbbb" : count of '1' at the end of "cccccccc" + + + + For the bit de-stuffing : + + destuff0 = used if the previous byte ended with '0' + destuff1 = used if the previous byte ended with '10' + destuff2 = used if the previous byte ended with '110' + destuff3 = used if the previous byte ended with '1110' + destuff4 = used if the previous byte ended with '11110' + destuff5 = used if the previous byte ended with '111110' + + those arrays are indexed by the byte to de-stuff. + + the data of those arrays are of the form (in binary): + "dbbbaaaa cccccccc" + with "cccccccc" : byte destuffed + "aaaa" : count of '1' at the end of the byte non destuffed + "bbb" : count of bits to use in the destuffed byte (8 less the count + of '0' deleted) less 1 (can be only 7, 6 or 5) + "d" : '1' if the byte non destuffed has more than 5 consecutive '1' + (flag or abort) +*/ + +#include <linux/types.h> +#include "tpam.h" + +typedef u8 BYTE; +typedef u16 WORD; +typedef u32 DWORD; +typedef u8 BOOL; + +#define TRUE 1 +#define FALSE 0 + +static WORD stuff0[] = +{ + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x041F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x043E, 0x045F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x149F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x047C, 0x047D, 0x14BE, 0x24DF, + 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087, + 0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F, + 0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097, + 0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x051F, + 0x10A0, 0x10A1, 0x10A2, 0x10A3, 0x10A4, 0x10A5, 0x10A6, 0x10A7, + 0x10A8, 0x10A9, 0x10AA, 0x10AB, 0x10AC, 0x10AD, 0x10AE, 0x10AF, + 0x10B0, 0x10B1, 0x10B2, 0x10B3, 0x10B4, 0x10B5, 0x10B6, 0x10B7, + 0x10B8, 0x10B9, 0x10BA, 0x10BB, 0x10BC, 0x10BD, 0x053E, 0x055F, + 0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7, + 0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF, + 0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7, + 0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x159F, + 0x30E0, 0x30E1, 0x30E2, 0x30E3, 0x30E4, 0x30E5, 0x30E6, 0x30E7, + 0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EE, 0x30EF, + 0x40F0, 0x40F1, 0x40F2, 0x40F3, 0x40F4, 0x40F5, 0x40F6, 0x40F7, + 0x50F8, 0x50F9, 0x50FA, 0x50FB, 0x057C, 0x057D, 0x15BE, 0x25DF, +}; + + +static WORD stuff1[] = +{ + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x040F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x042F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x044F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x043E, 0x046F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x148F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x14AF, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x24CF, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x047C, 0x047D, 0x14BE, 0x34EF, + 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087, + 0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x050F, + 0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097, + 0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x052F, + 0x10A0, 0x10A1, 0x10A2, 0x10A3, 0x10A4, 0x10A5, 0x10A6, 0x10A7, + 0x10A8, 0x10A9, 0x10AA, 0x10AB, 0x10AC, 0x10AD, 0x10AE, 0x054F, + 0x10B0, 0x10B1, 0x10B2, 0x10B3, 0x10B4, 0x10B5, 0x10B6, 0x10B7, + 0x10B8, 0x10B9, 0x10BA, 0x10BB, 0x10BC, 0x10BD, 0x053E, 0x056F, + 0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7, + 0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x158F, + 0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7, + 0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x15AF, + 0x30E0, 0x30E1, 0x30E2, 0x30E3, 0x30E4, 0x30E5, 0x30E6, 0x30E7, + 0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EE, 0x25CF, + 0x40F0, 0x40F1, 0x40F2, 0x40F3, 0x40F4, 0x40F5, 0x40F6, 0x40F7, + 0x50F8, 0x50F9, 0x50FA, 0x50FB, 0x057C, 0x057D, 0x15BE, 0x35EF, +}; + + +static WORD stuff2[] = +{ + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0407, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x0417, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0427, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x0437, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0447, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x0457, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0467, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x043E, 0x0477, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x1487, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x1497, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x14A7, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x14B7, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x24C7, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x24D7, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x34E7, + 0x0078, 0x0079, 0x007A, 0x007B, 0x047C, 0x047D, 0x14BE, 0x44F7, + 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x0507, + 0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x0517, + 0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x0527, + 0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x0537, + 0x10A0, 0x10A1, 0x10A2, 0x10A3, 0x10A4, 0x10A5, 0x10A6, 0x0547, + 0x10A8, 0x10A9, 0x10AA, 0x10AB, 0x10AC, 0x10AD, 0x10AE, 0x0557, + 0x10B0, 0x10B1, 0x10B2, 0x10B3, 0x10B4, 0x10B5, 0x10B6, 0x0567, + 0x10B8, 0x10B9, 0x10BA, 0x10BB, 0x10BC, 0x10BD, 0x053E, 0x0577, + 0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x1587, + 0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x1597, + 0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x15A7, + 0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x15B7, + 0x30E0, 0x30E1, 0x30E2, 0x30E3, 0x30E4, 0x30E5, 0x30E6, 0x25C7, + 0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EE, 0x25D7, + 0x40F0, 0x40F1, 0x40F2, 0x40F3, 0x40F4, 0x40F5, 0x40F6, 0x35E7, + 0x50F8, 0x50F9, 0x50FA, 0x50FB, 0x057C, 0x057D, 0x15BE, 0x45F7, +}; + + +static WORD stuff3[] = +{ + 0x0000, 0x0001, 0x0002, 0x0403, 0x0004, 0x0005, 0x0006, 0x040B, + 0x0008, 0x0009, 0x000A, 0x0413, 0x000C, 0x000D, 0x000E, 0x041B, + 0x0010, 0x0011, 0x0012, 0x0423, 0x0014, 0x0015, 0x0016, 0x042B, + 0x0018, 0x0019, 0x001A, 0x0433, 0x001C, 0x001D, 0x001E, 0x043B, + 0x0020, 0x0021, 0x0022, 0x0443, 0x0024, 0x0025, 0x0026, 0x044B, + 0x0028, 0x0029, 0x002A, 0x0453, 0x002C, 0x002D, 0x002E, 0x045B, + 0x0030, 0x0031, 0x0032, 0x0463, 0x0034, 0x0035, 0x0036, 0x046B, + 0x0038, 0x0039, 0x003A, 0x0473, 0x003C, 0x003D, 0x043E, 0x047B, + 0x0040, 0x0041, 0x0042, 0x1483, 0x0044, 0x0045, 0x0046, 0x148B, + 0x0048, 0x0049, 0x004A, 0x1493, 0x004C, 0x004D, 0x004E, 0x149B, + 0x0050, 0x0051, 0x0052, 0x14A3, 0x0054, 0x0055, 0x0056, 0x14AB, + 0x0058, 0x0059, 0x005A, 0x14B3, 0x005C, 0x005D, 0x005E, 0x14BB, + 0x0060, 0x0061, 0x0062, 0x24C3, 0x0064, 0x0065, 0x0066, 0x24CB, + 0x0068, 0x0069, 0x006A, 0x24D3, 0x006C, 0x006D, 0x006E, 0x24DB, + 0x0070, 0x0071, 0x0072, 0x34E3, 0x0074, 0x0075, 0x0076, 0x34EB, + 0x0078, 0x0079, 0x007A, 0x44F3, 0x047C, 0x047D, 0x14BE, 0x54FB, + 0x1080, 0x1081, 0x1082, 0x0503, 0x1084, 0x1085, 0x1086, 0x050B, + 0x1088, 0x1089, 0x108A, 0x0513, 0x108C, 0x108D, 0x108E, 0x051B, + 0x1090, 0x1091, 0x1092, 0x0523, 0x1094, 0x1095, 0x1096, 0x052B, + 0x1098, 0x1099, 0x109A, 0x0533, 0x109C, 0x109D, 0x109E, 0x053B, + 0x10A0, 0x10A1, 0x10A2, 0x0543, 0x10A4, 0x10A5, 0x10A6, 0x054B, + 0x10A8, 0x10A9, 0x10AA, 0x0553, 0x10AC, 0x10AD, 0x10AE, 0x055B, + 0x10B0, 0x10B1, 0x10B2, 0x0563, 0x10B4, 0x10B5, 0x10B6, 0x056B, + 0x10B8, 0x10B9, 0x10BA, 0x0573, 0x10BC, 0x10BD, 0x053E, 0x057B, + 0x20C0, 0x20C1, 0x20C2, 0x1583, 0x20C4, 0x20C5, 0x20C6, 0x158B, + 0x20C8, 0x20C9, 0x20CA, 0x1593, 0x20CC, 0x20CD, 0x20CE, 0x159B, + 0x20D0, 0x20D1, 0x20D2, 0x15A3, 0x20D4, 0x20D5, 0x20D6, 0x15AB, + 0x20D8, 0x20D9, 0x20DA, 0x15B3, 0x20DC, 0x20DD, 0x20DE, 0x15BB, + 0x30E0, 0x30E1, 0x30E2, 0x25C3, 0x30E4, 0x30E5, 0x30E6, 0x25CB, + 0x30E8, 0x30E9, 0x30EA, 0x25D3, 0x30EC, 0x30ED, 0x30EE, 0x25DB, + 0x40F0, 0x40F1, 0x40F2, 0x35E3, 0x40F4, 0x40F5, 0x40F6, 0x35EB, + 0x50F8, 0x50F9, 0x50FA, 0x45F3, 0x057C, 0x057D, 0x15BE, 0x55FB, +}; + + +static WORD stuff4[] = +{ + 0x0000, 0x0401, 0x0002, 0x0405, 0x0004, 0x0409, 0x0006, 0x040D, + 0x0008, 0x0411, 0x000A, 0x0415, 0x000C, 0x0419, 0x000E, 0x041D, + 0x0010, 0x0421, 0x0012, 0x0425, 0x0014, 0x0429, 0x0016, 0x042D, + 0x0018, 0x0431, 0x001A, 0x0435, 0x001C, 0x0439, 0x001E, 0x043D, + 0x0020, 0x0441, 0x0022, 0x0445, 0x0024, 0x0449, 0x0026, 0x044D, + 0x0028, 0x0451, 0x002A, 0x0455, 0x002C, 0x0459, 0x002E, 0x045D, + 0x0030, 0x0461, 0x0032, 0x0465, 0x0034, 0x0469, 0x0036, 0x046D, + 0x0038, 0x0471, 0x003A, 0x0475, 0x003C, 0x0479, 0x043E, 0x087D, + 0x0040, 0x1481, 0x0042, 0x1485, 0x0044, 0x1489, 0x0046, 0x148D, + 0x0048, 0x1491, 0x004A, 0x1495, 0x004C, 0x1499, 0x004E, 0x149D, + 0x0050, 0x14A1, 0x0052, 0x14A5, 0x0054, 0x14A9, 0x0056, 0x14AD, + 0x0058, 0x14B1, 0x005A, 0x14B5, 0x005C, 0x14B9, 0x005E, 0x14BD, + 0x0060, 0x24C1, 0x0062, 0x24C5, 0x0064, 0x24C9, 0x0066, 0x24CD, + 0x0068, 0x24D1, 0x006A, 0x24D5, 0x006C, 0x24D9, 0x006E, 0x24DD, + 0x0070, 0x34E1, 0x0072, 0x34E5, 0x0074, 0x34E9, 0x0076, 0x34ED, + 0x0078, 0x44F1, 0x007A, 0x44F5, 0x047C, 0x54F9, 0x14BE, 0x097D, + 0x1080, 0x0501, 0x1082, 0x0505, 0x1084, 0x0509, 0x1086, 0x050D, + 0x1088, 0x0511, 0x108A, 0x0515, 0x108C, 0x0519, 0x108E, 0x051D, + 0x1090, 0x0521, 0x1092, 0x0525, 0x1094, 0x0529, 0x1096, 0x052D, + 0x1098, 0x0531, 0x109A, 0x0535, 0x109C, 0x0539, 0x109E, 0x053D, + 0x10A0, 0x0541, 0x10A2, 0x0545, 0x10A4, 0x0549, 0x10A6, 0x054D, + 0x10A8, 0x0551, 0x10AA, 0x0555, 0x10AC, 0x0559, 0x10AE, 0x055D, + 0x10B0, 0x0561, 0x10B2, 0x0565, 0x10B4, 0x0569, 0x10B6, 0x056D, + 0x10B8, 0x0571, 0x10BA, 0x0575, 0x10BC, 0x0579, 0x053E, 0x0A7D, + 0x20C0, 0x1581, 0x20C2, 0x1585, 0x20C4, 0x1589, 0x20C6, 0x158D, + 0x20C8, 0x1591, 0x20CA, 0x1595, 0x20CC, 0x1599, 0x20CE, 0x159D, + 0x20D0, 0x15A1, 0x20D2, 0x15A5, 0x20D4, 0x15A9, 0x20D6, 0x15AD, + 0x20D8, 0x15B1, 0x20DA, 0x15B5, 0x20DC, 0x15B9, 0x20DE, 0x15BD, + 0x30E0, 0x25C1, 0x30E2, 0x25C5, 0x30E4, 0x25C9, 0x30E6, 0x25CD, + 0x30E8, 0x25D1, 0x30EA, 0x25D5, 0x30EC, 0x25D9, 0x30EE, 0x25DD, + 0x40F0, 0x35E1, 0x40F2, 0x35E5, 0x40F4, 0x35E9, 0x40F6, 0x35ED, + 0x50F8, 0x45F1, 0x50FA, 0x45F5, 0x057C, 0x55F9, 0x15BE, 0x0B7D, +}; + + +static WORD stuff5[] = +{ + 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040A, 0x040C, 0x040E, + 0x0410, 0x0412, 0x0414, 0x0416, 0x0418, 0x041A, 0x041C, 0x041E, + 0x0420, 0x0422, 0x0424, 0x0426, 0x0428, 0x042A, 0x042C, 0x042E, + 0x0430, 0x0432, 0x0434, 0x0436, 0x0438, 0x043A, 0x043C, 0x083E, + 0x0440, 0x0442, 0x0444, 0x0446, 0x0448, 0x044A, 0x044C, 0x044E, + 0x0450, 0x0452, 0x0454, 0x0456, 0x0458, 0x045A, 0x045C, 0x045E, + 0x0460, 0x0462, 0x0464, 0x0466, 0x0468, 0x046A, 0x046C, 0x046E, + 0x0470, 0x0472, 0x0474, 0x0476, 0x0478, 0x047A, 0x087C, 0x18BE, + 0x1480, 0x1482, 0x1484, 0x1486, 0x1488, 0x148A, 0x148C, 0x148E, + 0x1490, 0x1492, 0x1494, 0x1496, 0x1498, 0x149A, 0x149C, 0x149E, + 0x14A0, 0x14A2, 0x14A4, 0x14A6, 0x14A8, 0x14AA, 0x14AC, 0x14AE, + 0x14B0, 0x14B2, 0x14B4, 0x14B6, 0x14B8, 0x14BA, 0x14BC, 0x093E, + 0x24C0, 0x24C2, 0x24C4, 0x24C6, 0x24C8, 0x24CA, 0x24CC, 0x24CE, + 0x24D0, 0x24D2, 0x24D4, 0x24D6, 0x24D8, 0x24DA, 0x24DC, 0x24DE, + 0x34E0, 0x34E2, 0x34E4, 0x34E6, 0x34E8, 0x34EA, 0x34EC, 0x34EE, + 0x44F0, 0x44F2, 0x44F4, 0x44F6, 0x54F8, 0x54FA, 0x097C, 0x19BE, + 0x0500, 0x0502, 0x0504, 0x0506, 0x0508, 0x050A, 0x050C, 0x050E, + 0x0510, 0x0512, 0x0514, 0x0516, 0x0518, 0x051A, 0x051C, 0x051E, + 0x0520, 0x0522, 0x0524, 0x0526, 0x0528, 0x052A, 0x052C, 0x052E, + 0x0530, 0x0532, 0x0534, 0x0536, 0x0538, 0x053A, 0x053C, 0x0A3E, + 0x0540, 0x0542, 0x0544, 0x0546, 0x0548, 0x054A, 0x054C, 0x054E, + 0x0550, 0x0552, 0x0554, 0x0556, 0x0558, 0x055A, 0x055C, 0x055E, + 0x0560, 0x0562, 0x0564, 0x0566, 0x0568, 0x056A, 0x056C, 0x056E, + 0x0570, 0x0572, 0x0574, 0x0576, 0x0578, 0x057A, 0x0A7C, 0x1ABE, + 0x1580, 0x1582, 0x1584, 0x1586, 0x1588, 0x158A, 0x158C, 0x158E, + 0x1590, 0x1592, 0x1594, 0x1596, 0x1598, 0x159A, 0x159C, 0x159E, + 0x15A0, 0x15A2, 0x15A4, 0x15A6, 0x15A8, 0x15AA, 0x15AC, 0x15AE, + 0x15B0, 0x15B2, 0x15B4, 0x15B6, 0x15B8, 0x15BA, 0x15BC, 0x0B3E, + 0x25C0, 0x25C2, 0x25C4, 0x25C6, 0x25C8, 0x25CA, 0x25CC, 0x25CE, + 0x25D0, 0x25D2, 0x25D4, 0x25D6, 0x25D8, 0x25DA, 0x25DC, 0x25DE, + 0x35E0, 0x35E2, 0x35E4, 0x35E6, 0x35E8, 0x35EA, 0x35EC, 0x35EE, + 0x45F0, 0x45F2, 0x45F4, 0x45F6, 0x55F8, 0x55FA, 0x0B7C, 0x1BBE, +}; + +static WORD destuff0[] = +{ + 0x7000, 0x7001, 0x7002, 0x7003, 0x7004, 0x7005, 0x7006, 0x7007, + 0x7008, 0x7009, 0x700A, 0x700B, 0x700C, 0x700D, 0x700E, 0x700F, + 0x7010, 0x7011, 0x7012, 0x7013, 0x7014, 0x7015, 0x7016, 0x7017, + 0x7018, 0x7019, 0x701A, 0x701B, 0x701C, 0x701D, 0x701E, 0x601F, + 0x7020, 0x7021, 0x7022, 0x7023, 0x7024, 0x7025, 0x7026, 0x7027, + 0x7028, 0x7029, 0x702A, 0x702B, 0x702C, 0x702D, 0x702E, 0x702F, + 0x7030, 0x7031, 0x7032, 0x7033, 0x7034, 0x7035, 0x7036, 0x7037, + 0x7038, 0x7039, 0x703A, 0x703B, 0x703C, 0x703D, 0x603E, 0xF03F, + 0x7040, 0x7041, 0x7042, 0x7043, 0x7044, 0x7045, 0x7046, 0x7047, + 0x7048, 0x7049, 0x704A, 0x704B, 0x704C, 0x704D, 0x704E, 0x704F, + 0x7050, 0x7051, 0x7052, 0x7053, 0x7054, 0x7055, 0x7056, 0x7057, + 0x7058, 0x7059, 0x705A, 0x705B, 0x705C, 0x705D, 0x705E, 0x603F, + 0x7060, 0x7061, 0x7062, 0x7063, 0x7064, 0x7065, 0x7066, 0x7067, + 0x7068, 0x7069, 0x706A, 0x706B, 0x706C, 0x706D, 0x706E, 0x706F, + 0x7070, 0x7071, 0x7072, 0x7073, 0x7074, 0x7075, 0x7076, 0x7077, + 0x7078, 0x7079, 0x707A, 0x707B, 0x607C, 0x607D, 0xF07E, 0xF07F, + 0x7180, 0x7181, 0x7182, 0x7183, 0x7184, 0x7185, 0x7186, 0x7187, + 0x7188, 0x7189, 0x718A, 0x718B, 0x718C, 0x718D, 0x718E, 0x718F, + 0x7190, 0x7191, 0x7192, 0x7193, 0x7194, 0x7195, 0x7196, 0x7197, + 0x7198, 0x7199, 0x719A, 0x719B, 0x719C, 0x719D, 0x719E, 0x615F, + 0x71A0, 0x71A1, 0x71A2, 0x71A3, 0x71A4, 0x71A5, 0x71A6, 0x71A7, + 0x71A8, 0x71A9, 0x71AA, 0x71AB, 0x71AC, 0x71AD, 0x71AE, 0x71AF, + 0x71B0, 0x71B1, 0x71B2, 0x71B3, 0x71B4, 0x71B5, 0x71B6, 0x71B7, + 0x71B8, 0x71B9, 0x71BA, 0x71BB, 0x71BC, 0x71BD, 0x617E, 0xF1BF, + 0x72C0, 0x72C1, 0x72C2, 0x72C3, 0x72C4, 0x72C5, 0x72C6, 0x72C7, + 0x72C8, 0x72C9, 0x72CA, 0x72CB, 0x72CC, 0x72CD, 0x72CE, 0x72CF, + 0x72D0, 0x72D1, 0x72D2, 0x72D3, 0x72D4, 0x72D5, 0x72D6, 0x72D7, + 0x72D8, 0x72D9, 0x72DA, 0x72DB, 0x72DC, 0x72DD, 0x72DE, 0x627F, + 0x73E0, 0x73E1, 0x73E2, 0x73E3, 0x73E4, 0x73E5, 0x73E6, 0x73E7, + 0x73E8, 0x73E9, 0x73EA, 0x73EB, 0x73EC, 0x73ED, 0x73EE, 0x73EF, + 0x74F0, 0x74F1, 0x74F2, 0x74F3, 0x74F4, 0x74F5, 0x74F6, 0x74F7, + 0x75F8, 0x75F9, 0x75FA, 0x75FB, 0xF6FC, 0xF6FD, 0xF7FE, 0xF8FF, +}; + + +static WORD destuff1[] = +{ + 0x7000, 0x7001, 0x7002, 0x7003, 0x7004, 0x7005, 0x7006, 0x7007, + 0x7008, 0x7009, 0x700A, 0x700B, 0x700C, 0x700D, 0x700E, 0x600F, + 0x7010, 0x7011, 0x7012, 0x7013, 0x7014, 0x7015, 0x7016, 0x7017, + 0x7018, 0x7019, 0x701A, 0x701B, 0x701C, 0x701D, 0x701E, 0xF01F, + 0x7020, 0x7021, 0x7022, 0x7023, 0x7024, 0x7025, 0x7026, 0x7027, + 0x7028, 0x7029, 0x702A, 0x702B, 0x702C, 0x702D, 0x702E, 0x601F, + 0x7030, 0x7031, 0x7032, 0x7033, 0x7034, 0x7035, 0x7036, 0x7037, + 0x7038, 0x7039, 0x703A, 0x703B, 0x703C, 0x703D, 0x603E, 0xF03F, + 0x7040, 0x7041, 0x7042, 0x7043, 0x7044, 0x7045, 0x7046, 0x7047, + 0x7048, 0x7049, 0x704A, 0x704B, 0x704C, 0x704D, 0x704E, 0x602F, + 0x7050, 0x7051, 0x7052, 0x7053, 0x7054, 0x7055, 0x7056, 0x7057, + 0x7058, 0x7059, 0x705A, 0x705B, 0x705C, 0x705D, 0x705E, 0xF05F, + 0x7060, 0x7061, 0x7062, 0x7063, 0x7064, 0x7065, 0x7066, 0x7067, + 0x7068, 0x7069, 0x706A, 0x706B, 0x706C, 0x706D, 0x706E, 0x603F, + 0x7070, 0x7071, 0x7072, 0x7073, 0x7074, 0x7075, 0x7076, 0x7077, + 0x7078, 0x7079, 0x707A, 0x707B, 0x607C, 0x607D, 0xF07E, 0xF07F, + 0x7180, 0x7181, 0x7182, 0x7183, 0x7184, 0x7185, 0x7186, 0x7187, + 0x7188, 0x7189, 0x718A, 0x718B, 0x718C, 0x718D, 0x718E, 0x614F, + 0x7190, 0x7191, 0x7192, 0x7193, 0x7194, 0x7195, 0x7196, 0x7197, + 0x7198, 0x7199, 0x719A, 0x719B, 0x719C, 0x719D, 0x719E, 0xF19F, + 0x71A0, 0x71A1, 0x71A2, 0x71A3, 0x71A4, 0x71A5, 0x71A6, 0x71A7, + 0x71A8, 0x71A9, 0x71AA, 0x71AB, 0x71AC, 0x71AD, 0x71AE, 0x615F, + 0x71B0, 0x71B1, 0x71B2, 0x71B3, 0x71B4, 0x71B5, 0x71B6, 0x71B7, + 0x71B8, 0x71B9, 0x71BA, 0x71BB, 0x71BC, 0x71BD, 0x617E, 0xF1BF, + 0x72C0, 0x72C1, 0x72C2, 0x72C3, 0x72C4, 0x72C5, 0x72C6, 0x72C7, + 0x72C8, 0x72C9, 0x72CA, 0x72CB, 0x72CC, 0x72CD, 0x72CE, 0x626F, + 0x72D0, 0x72D1, 0x72D2, 0x72D3, 0x72D4, 0x72D5, 0x72D6, 0x72D7, + 0x72D8, 0x72D9, 0x72DA, 0x72DB, 0x72DC, 0x72DD, 0x72DE, 0xF2DF, + 0x73E0, 0x73E1, 0x73E2, 0x73E3, 0x73E4, 0x73E5, 0x73E6, 0x73E7, + 0x73E8, 0x73E9, 0x73EA, 0x73EB, 0x73EC, 0x73ED, 0x73EE, 0x637F, + 0x74F0, 0x74F1, 0x74F2, 0x74F3, 0x74F4, 0x74F5, 0x74F6, 0x74F7, + 0x75F8, 0x75F9, 0x75FA, 0x75FB, 0xF6FC, 0xF6FD, 0xF7FE, 0xF9FF, +}; + + +static WORD destuff2[] = +{ + 0x7000, 0x7001, 0x7002, 0x7003, 0x7004, 0x7005, 0x7006, 0x6007, + 0x7008, 0x7009, 0x700A, 0x700B, 0x700C, 0x700D, 0x700E, 0xF00F, + 0x7010, 0x7011, 0x7012, 0x7013, 0x7014, 0x7015, 0x7016, 0x600F, + 0x7018, 0x7019, 0x701A, 0x701B, 0x701C, 0x701D, 0x701E, 0xF01F, + 0x7020, 0x7021, 0x7022, 0x7023, 0x7024, 0x7025, 0x7026, 0x6017, + 0x7028, 0x7029, 0x702A, 0x702B, 0x702C, 0x702D, 0x702E, 0xF02F, + 0x7030, 0x7031, 0x7032, 0x7033, 0x7034, 0x7035, 0x7036, 0x601F, + 0x7038, 0x7039, 0x703A, 0x703B, 0x703C, 0x703D, 0x603E, 0xF03F, + 0x7040, 0x7041, 0x7042, 0x7043, 0x7044, 0x7045, 0x7046, 0x6027, + 0x7048, 0x7049, 0x704A, 0x704B, 0x704C, 0x704D, 0x704E, 0xF04F, + 0x7050, 0x7051, 0x7052, 0x7053, 0x7054, 0x7055, 0x7056, 0x602F, + 0x7058, 0x7059, 0x705A, 0x705B, 0x705C, 0x705D, 0x705E, 0xF05F, + 0x7060, 0x7061, 0x7062, 0x7063, 0x7064, 0x7065, 0x7066, 0x6037, + 0x7068, 0x7069, 0x706A, 0x706B, 0x706C, 0x706D, 0x706E, 0xF06F, + 0x7070, 0x7071, 0x7072, 0x7073, 0x7074, 0x7075, 0x7076, 0x603F, + 0x7078, 0x7079, 0x707A, 0x707B, 0x607C, 0x607D, 0xF07E, 0xF07F, + 0x7180, 0x7181, 0x7182, 0x7183, 0x7184, 0x7185, 0x7186, 0x6147, + 0x7188, 0x7189, 0x718A, 0x718B, 0x718C, 0x718D, 0x718E, 0xF18F, + 0x7190, 0x7191, 0x7192, 0x7193, 0x7194, 0x7195, 0x7196, 0x614F, + 0x7198, 0x7199, 0x719A, 0x719B, 0x719C, 0x719D, 0x719E, 0xF19F, + 0x71A0, 0x71A1, 0x71A2, 0x71A3, 0x71A4, 0x71A5, 0x71A6, 0x6157, + 0x71A8, 0x71A9, 0x71AA, 0x71AB, 0x71AC, 0x71AD, 0x71AE, 0xF1AF, + 0x71B0, 0x71B1, 0x71B2, 0x71B3, 0x71B4, 0x71B5, 0x71B6, 0x615F, + 0x71B8, 0x71B9, 0x71BA, 0x71BB, 0x71BC, 0x71BD, 0x617E, 0xF1BF, + 0x72C0, 0x72C1, 0x72C2, 0x72C3, 0x72C4, 0x72C5, 0x72C6, 0x6267, + 0x72C8, 0x72C9, 0x72CA, 0x72CB, 0x72CC, 0x72CD, 0x72CE, 0xF2CF, + 0x72D0, 0x72D1, 0x72D2, 0x72D3, 0x72D4, 0x72D5, 0x72D6, 0x626F, + 0x72D8, 0x72D9, 0x72DA, 0x72DB, 0x72DC, 0x72DD, 0x72DE, 0xF2DF, + 0x73E0, 0x73E1, 0x73E2, 0x73E3, 0x73E4, 0x73E5, 0x73E6, 0x6377, + 0x73E8, 0x73E9, 0x73EA, 0x73EB, 0x73EC, 0x73ED, 0x73EE, 0xF3EF, + 0x74F0, 0x74F1, 0x74F2, 0x74F3, 0x74F4, 0x74F5, 0x74F6, 0x647F, + 0x75F8, 0x75F9, 0x75FA, 0x75FB, 0xF6FC, 0xF6FD, 0xF7FE, 0xFAFF, +}; + + +static WORD destuff3[] = +{ + 0x7000, 0x7001, 0x7002, 0x6003, 0x7004, 0x7005, 0x7006, 0xF007, + 0x7008, 0x7009, 0x700A, 0x6007, 0x700C, 0x700D, 0x700E, 0xF00F, + 0x7010, 0x7011, 0x7012, 0x600B, 0x7014, 0x7015, 0x7016, 0xF017, + 0x7018, 0x7019, 0x701A, 0x600F, 0x701C, 0x701D, 0x701E, 0xF01F, + 0x7020, 0x7021, 0x7022, 0x6013, 0x7024, 0x7025, 0x7026, 0xF027, + 0x7028, 0x7029, 0x702A, 0x6017, 0x702C, 0x702D, 0x702E, 0xF02F, + 0x7030, 0x7031, 0x7032, 0x601B, 0x7034, 0x7035, 0x7036, 0xF037, + 0x7038, 0x7039, 0x703A, 0x601F, 0x703C, 0x703D, 0x603E, 0xF03F, + 0x7040, 0x7041, 0x7042, 0x6023, 0x7044, 0x7045, 0x7046, 0xF047, + 0x7048, 0x7049, 0x704A, 0x6027, 0x704C, 0x704D, 0x704E, 0xF04F, + 0x7050, 0x7051, 0x7052, 0x602B, 0x7054, 0x7055, 0x7056, 0xF057, + 0x7058, 0x7059, 0x705A, 0x602F, 0x705C, 0x705D, 0x705E, 0xF05F, + 0x7060, 0x7061, 0x7062, 0x6033, 0x7064, 0x7065, 0x7066, 0xF067, + 0x7068, 0x7069, 0x706A, 0x6037, 0x706C, 0x706D, 0x706E, 0xF06F, + 0x7070, 0x7071, 0x7072, 0x603B, 0x7074, 0x7075, 0x7076, 0xF077, + 0x7078, 0x7079, 0x707A, 0x603F, 0x607C, 0x607D, 0xF07E, 0xF07F, + 0x7180, 0x7181, 0x7182, 0x6143, 0x7184, 0x7185, 0x7186, 0xF187, + 0x7188, 0x7189, 0x718A, 0x6147, 0x718C, 0x718D, 0x718E, 0xF18F, + 0x7190, 0x7191, 0x7192, 0x614B, 0x7194, 0x7195, 0x7196, 0xF197, + 0x7198, 0x7199, 0x719A, 0x614F, 0x719C, 0x719D, 0x719E, 0xF19F, + 0x71A0, 0x71A1, 0x71A2, 0x6153, 0x71A4, 0x71A5, 0x71A6, 0xF1A7, + 0x71A8, 0x71A9, 0x71AA, 0x6157, 0x71AC, 0x71AD, 0x71AE, 0xF1AF, + 0x71B0, 0x71B1, 0x71B2, 0x615B, 0x71B4, 0x71B5, 0x71B6, 0xF1B7, + 0x71B8, 0x71B9, 0x71BA, 0x615F, 0x71BC, 0x71BD, 0x617E, 0xF1BF, + 0x72C0, 0x72C1, 0x72C2, 0x6263, 0x72C4, 0x72C5, 0x72C6, 0xF2C7, + 0x72C8, 0x72C9, 0x72CA, 0x6267, 0x72CC, 0x72CD, 0x72CE, 0xF2CF, + 0x72D0, 0x72D1, 0x72D2, 0x626B, 0x72D4, 0x72D5, 0x72D6, 0xF2D7, + 0x72D8, 0x72D9, 0x72DA, 0x626F, 0x72DC, 0x72DD, 0x72DE, 0xF2DF, + 0x73E0, 0x73E1, 0x73E2, 0x6373, 0x73E4, 0x73E5, 0x73E6, 0xF3E7, + 0x73E8, 0x73E9, 0x73EA, 0x6377, 0x73EC, 0x73ED, 0x73EE, 0xF3EF, + 0x74F0, 0x74F1, 0x74F2, 0x647B, 0x74F4, 0x74F5, 0x74F6, 0xF4F7, + 0x75F8, 0x75F9, 0x75FA, 0x657F, 0xF6FC, 0xF6FD, 0xF7FE, 0xFBFF, +}; + + +static WORD destuff4[] = +{ + 0x7000, 0x6001, 0x7002, 0xF003, 0x7004, 0x6003, 0x7006, 0xF007, + 0x7008, 0x6005, 0x700A, 0xF00B, 0x700C, 0x6007, 0x700E, 0xF00F, + 0x7010, 0x6009, 0x7012, 0xF013, 0x7014, 0x600B, 0x7016, 0xF017, + 0x7018, 0x600D, 0x701A, 0xF01B, 0x701C, 0x600F, 0x701E, 0xF01F, + 0x7020, 0x6011, 0x7022, 0xF023, 0x7024, 0x6013, 0x7026, 0xF027, + 0x7028, 0x6015, 0x702A, 0xF02B, 0x702C, 0x6017, 0x702E, 0xF02F, + 0x7030, 0x6019, 0x7032, 0xF033, 0x7034, 0x601B, 0x7036, 0xF037, + 0x7038, 0x601D, 0x703A, 0xF03B, 0x703C, 0x601F, 0x603E, 0xF03F, + 0x7040, 0x6021, 0x7042, 0xF043, 0x7044, 0x6023, 0x7046, 0xF047, + 0x7048, 0x6025, 0x704A, 0xF04B, 0x704C, 0x6027, 0x704E, 0xF04F, + 0x7050, 0x6029, 0x7052, 0xF053, 0x7054, 0x602B, 0x7056, 0xF057, + 0x7058, 0x602D, 0x705A, 0xF05B, 0x705C, 0x602F, 0x705E, 0xF05F, + 0x7060, 0x6031, 0x7062, 0xF063, 0x7064, 0x6033, 0x7066, 0xF067, + 0x7068, 0x6035, 0x706A, 0xF06B, 0x706C, 0x6037, 0x706E, 0xF06F, + 0x7070, 0x6039, 0x7072, 0xF073, 0x7074, 0x603B, 0x7076, 0xF077, + 0x7078, 0x603D, 0x707A, 0xF07B, 0x607C, 0x503F, 0xF07E, 0xF07F, + 0x7180, 0x6141, 0x7182, 0xF183, 0x7184, 0x6143, 0x7186, 0xF187, + 0x7188, 0x6145, 0x718A, 0xF18B, 0x718C, 0x6147, 0x718E, 0xF18F, + 0x7190, 0x6149, 0x7192, 0xF193, 0x7194, 0x614B, 0x7196, 0xF197, + 0x7198, 0x614D, 0x719A, 0xF19B, 0x719C, 0x614F, 0x719E, 0xF19F, + 0x71A0, 0x6151, 0x71A2, 0xF1A3, 0x71A4, 0x6153, 0x71A6, 0xF1A7, + 0x71A8, 0x6155, 0x71AA, 0xF1AB, 0x71AC, 0x6157, 0x71AE, 0xF1AF, + 0x71B0, 0x6159, 0x71B2, 0xF1B3, 0x71B4, 0x615B, 0x71B6, 0xF1B7, + 0x71B8, 0x615D, 0x71BA, 0xF1BB, 0x71BC, 0x615F, 0x617E, 0xF1BF, + 0x72C0, 0x6261, 0x72C2, 0xF2C3, 0x72C4, 0x6263, 0x72C6, 0xF2C7, + 0x72C8, 0x6265, 0x72CA, 0xF2CB, 0x72CC, 0x6267, 0x72CE, 0xF2CF, + 0x72D0, 0x6269, 0x72D2, 0xF2D3, 0x72D4, 0x626B, 0x72D6, 0xF2D7, + 0x72D8, 0x626D, 0x72DA, 0xF2DB, 0x72DC, 0x626F, 0x72DE, 0xF2DF, + 0x73E0, 0x6371, 0x73E2, 0xF3E3, 0x73E4, 0x6373, 0x73E6, 0xF3E7, + 0x73E8, 0x6375, 0x73EA, 0xF3EB, 0x73EC, 0x6377, 0x73EE, 0xF3EF, + 0x74F0, 0x6479, 0x74F2, 0xF4F3, 0x74F4, 0x647B, 0x74F6, 0xF4F7, + 0x75F8, 0x657D, 0x75FA, 0xF5FB, 0xF6FC, 0xE67F, 0xF7FE, 0xFCFF, +}; + + +static WORD destuff5[] = +{ + 0x6000, 0xF001, 0x6001, 0xF003, 0x6002, 0xF005, 0x6003, 0xF007, + 0x6004, 0xF009, 0x6005, 0xF00B, 0x6006, 0xF00D, 0x6007, 0xF00F, + 0x6008, 0xF011, 0x6009, 0xF013, 0x600A, 0xF015, 0x600B, 0xF017, + 0x600C, 0xF019, 0x600D, 0xF01B, 0x600E, 0xF01D, 0x600F, 0xF01F, + 0x6010, 0xF021, 0x6011, 0xF023, 0x6012, 0xF025, 0x6013, 0xF027, + 0x6014, 0xF029, 0x6015, 0xF02B, 0x6016, 0xF02D, 0x6017, 0xF02F, + 0x6018, 0xF031, 0x6019, 0xF033, 0x601A, 0xF035, 0x601B, 0xF037, + 0x601C, 0xF039, 0x601D, 0xF03B, 0x601E, 0xF03D, 0x501F, 0xF03F, + 0x6020, 0xF041, 0x6021, 0xF043, 0x6022, 0xF045, 0x6023, 0xF047, + 0x6024, 0xF049, 0x6025, 0xF04B, 0x6026, 0xF04D, 0x6027, 0xF04F, + 0x6028, 0xF051, 0x6029, 0xF053, 0x602A, 0xF055, 0x602B, 0xF057, + 0x602C, 0xF059, 0x602D, 0xF05B, 0x602E, 0xF05D, 0x602F, 0xF05F, + 0x6030, 0xF061, 0x6031, 0xF063, 0x6032, 0xF065, 0x6033, 0xF067, + 0x6034, 0xF069, 0x6035, 0xF06B, 0x6036, 0xF06D, 0x6037, 0xF06F, + 0x6038, 0xF071, 0x6039, 0xF073, 0x603A, 0xF075, 0x603B, 0xF077, + 0x603C, 0xF079, 0x603D, 0xF07B, 0x503E, 0xE07D, 0xE03F, 0xF07F, + 0x6140, 0xF181, 0x6141, 0xF183, 0x6142, 0xF185, 0x6143, 0xF187, + 0x6144, 0xF189, 0x6145, 0xF18B, 0x6146, 0xF18D, 0x6147, 0xF18F, + 0x6148, 0xF191, 0x6149, 0xF193, 0x614A, 0xF195, 0x614B, 0xF197, + 0x614C, 0xF199, 0x614D, 0xF19B, 0x614E, 0xF19D, 0x614F, 0xF19F, + 0x6150, 0xF1A1, 0x6151, 0xF1A3, 0x6152, 0xF1A5, 0x6153, 0xF1A7, + 0x6154, 0xF1A9, 0x6155, 0xF1AB, 0x6156, 0xF1AD, 0x6157, 0xF1AF, + 0x6158, 0xF1B1, 0x6159, 0xF1B3, 0x615A, 0xF1B5, 0x615B, 0xF1B7, + 0x615C, 0xF1B9, 0x615D, 0xF1BB, 0x615E, 0xF1BD, 0x513F, 0xF1BF, + 0x6260, 0xF2C1, 0x6261, 0xF2C3, 0x6262, 0xF2C5, 0x6263, 0xF2C7, + 0x6264, 0xF2C9, 0x6265, 0xF2CB, 0x6266, 0xF2CD, 0x6267, 0xF2CF, + 0x6268, 0xF2D1, 0x6269, 0xF2D3, 0x626A, 0xF2D5, 0x626B, 0xF2D7, + 0x626C, 0xF2D9, 0x626D, 0xF2DB, 0x626E, 0xF2DD, 0x626F, 0xF2DF, + 0x6370, 0xF3E1, 0x6371, 0xF3E3, 0x6372, 0xF3E5, 0x6373, 0xF3E7, + 0x6374, 0xF3E9, 0x6375, 0xF3EB, 0x6376, 0xF3ED, 0x6377, 0xF3EF, + 0x6478, 0xF4F1, 0x6479, 0xF4F3, 0x647A, 0xF4F5, 0x647B, 0xF4F7, + 0x657C, 0xF5F9, 0x657D, 0xF5FB, 0xE67E, 0xF6FD, 0xE77F, 0xFDFF, +}; + + +static WORD * stuffs[] = { stuff0, stuff1, stuff2, stuff3, stuff4, stuff5 }; +WORD * destuffs[] = { destuff0, destuff1, destuff2, destuff3, destuff4, destuff5 }; + + +/*- AuverTech Telecom -------------------------------------------------------+ + | | + | @Function : hdlc_encode | + | @Author : Cyrille Boudon | + | | + +---------------------------------------------------------------------------+ + | | + | @Param : BYTE *pbyBuffIn IN, array of bytes to encode | + | @Param : BYTE *pbyBuffOut OUT, array of bytes encoded | + | @Param : DWORD *pdwInitialShift INOUT, initial shift | + | @Param : DWORD dwLength IN, count of bytes to encode | + | | + | @Return : DWORD count of bytes encoded | + | | + +------------------------------- @Abstract ---------------------------------+ + | | + | Bit stuffing of thz array pbyBuffIn with the insertion of a flag at the | + | beginning and the end, using the initial shift (due to the emission of | + | previous frames). The last byte can be used to insert flags (by outputting| + | the flag N times) before the next frame. The initial shift is updated at | + | the end of the algorithm for the next frame. Its signification is: for the| + | flags shifted like "1100111111001111" *pdwInitialShift = 3. At the | + | beginning (for the first frame), the shift must be initialized to 0. | + | | + +---------------------------------------------------------------------------*/ +DWORD hdlc_encode(BYTE *pbyBuffIn, BYTE *pbyBuffOut, + DWORD *pdwInitialShift, DWORD dwLength) +{ + DWORD dwShifter; // temporary variable + DWORD dwShiftNb; // shift due to the insertion of '0' + DWORD dwState; // count of '1' at the end of the current byte + DWORD dwNb; // length of the encoded array + BYTE byCarry; // carry due to the shift + BYTE byNewCarry; // temporary variable + BYTE byCharIn; // byte being encoded + BYTE byCarryMSB; // lost bit of the carry if dwShiftNb=7 and 2 '0' inserted + WORD woDecal; // temporary variable + WORD woInfo; // data read in the arrays + BOOL bContinue; // true until the two last bytes + BOOL bContinue2; // true until the last byte + + bContinue = TRUE; + bContinue2 = TRUE; + dwShiftNb = 0; + byCarry = 0; + dwState = 0; + woDecal = 0x7E; + byCarryMSB = 0xFF; + dwNb = 1; // length to 1 to account for the first flag + + /*----------------------------- + | insert the flag using the + | shift given by + | *pdwInitialShift) + +-----------------------------*/ + * pbyBuffOut ++ = 0x7E7E >> *pdwInitialShift; + + /*----------------------------- + | main loop + +-----------------------------*/ + while (dwLength--) + { + byCharIn = *pbyBuffIn ++; + +/*----------------------------- + | go back here to treat the + | carry when its length + | is over 7 and for the first + | byte (with flag) + +-----------------------------*/ +carry: + + dwNb ++; + + /*----------------------------- + | shift the byte to get the + | byte to encode (without + | taking into account the + | initial shift) + +-----------------------------*/ + if (dwShiftNb) + { + dwShifter = byCharIn << dwShiftNb; + byNewCarry = dwShifter >> 8; + byCharIn = dwShifter | byCarry; + byCarry = byNewCarry; + } + + /*----------------------------- + | get the data from the arrays + | and take into account the + | initial shift for the byte + | to encode + +-----------------------------*/ + woInfo = stuffs[dwState][byCharIn]; + woDecal |= (woInfo & 0x00FF) << 8; + * pbyBuffOut ++ = woDecal >> *pdwInitialShift; + woDecal = woInfo & 0x00FF; + dwState = woInfo >> 12; + + /*----------------------------- + | treat the lost bit if we had + | a carry overflow + +-----------------------------*/ + if (byCarryMSB != 0xFF) + { + if (!dwShiftNb) + { + if(byCarryMSB) + byCarry = 1; + dwShiftNb = 1; + } + byCarryMSB = 0xFF; + } + + /*----------------------------- + | if one '0' get inserted, we + | have to calculate the new + | carry and the new shift + +-----------------------------*/ + if (woInfo & 0x0F00) + { + byCarryMSB = byCarry & 0x40; + byCarry <<= (woInfo & 0x0C00) >> 10; + byCarry |= (woInfo & 0x0300) >> 8; + dwShiftNb += (woInfo & 0x0C00) >> 10; + } + + /*----------------------------- + | if the carry is a whole byte + | we use it as a byte to encode + +-----------------------------*/ + if (dwShiftNb > 7) + { + if (dwShiftNb == 8) + byCarryMSB = 0xFF; + dwShiftNb = 0; + byCharIn = byCarry; + byCarry = 0; + goto carry; + } + + /*----------------------------- + | at the end of the array + +-----------------------------*/ + if (!dwLength) + { + /*----------------------------- + | take into account the bits + | set in the carry + +-----------------------------*/ + if (bContinue) + { + bContinue = FALSE; + byCharIn = 0; + goto carry; + } + + /*----------------------------- + | treat the last byte if we + | had a carry overflow + +-----------------------------*/ + if (bContinue2 && ((8 - *pdwInitialShift) + dwShiftNb) > 7) + { + bContinue2 = FALSE; + byCharIn = 0; + goto carry; + } + + /*----------------------------- + | Calculate the new shift + +-----------------------------*/ + *pdwInitialShift = ((8 - *pdwInitialShift) + dwShiftNb)%8; + + /*----------------------------- + | Add a flag at the end of the + | carry and a full flag + +-----------------------------*/ + pbyBuffOut--; + *pbyBuffOut++ |= 0x7E << *pdwInitialShift; + byCarry = 0x7E7E >> (8 - *pdwInitialShift); + *pbyBuffOut++ = byCarry; + *pbyBuffOut++ = byCarry; + dwNb += 2; + } + } + + /*------------------------------- + | Pad the array to a multiple + | of 64 bytes. + +-------------------------------*/ + for(;dwNb%64;dwNb++) + *pbyBuffOut ++ = byCarry; + + *pdwInitialShift = (8 - *pdwInitialShift)%8; + + return dwNb; +} + + + +/*- AuverTech Telecom -------------------------------------------------------+ + | | + | @Function : hdlc_decode | + | @Author : Cyrille Boudon | + | | + +---------------------------------------------------------------------------+ + | | + | @Param : BYTE * pbyBuffIn IN, array of bytes to decode | + | @Param : BYTE * pbyBuffOut OUT, array of decoded bytes | + | @Param : DWORD dwLength IN, count of bytes to decode | + | | + | @Return : DWORD count of decoded bytes | + | | + +------------------------------- @Abstract ---------------------------------+ + | | + | Bit de-stuffing of the array pbyBuffIn. There has to be at least 1 full | + | flag at the beginning. At the end there has to be a flag or an abort (more| + | than 6 consecutive '1'). | + | If an abort is encountered, the returned count is '0'. | + | | + +---------------------------------------------------------------------------*/ +DWORD hdlc_decode(BYTE * pbyBuffIn, BYTE * pbyBuffOut, DWORD dwLength) +{ + BYTE byCharIn; // byte being decoded + BYTE byCarry; // current carry + WORD woInfo; // data read in the arrays + WORD woNb1; // count of '1' at the end of the previous byte + BYTE byShift; // shift of the first flag + DWORD dwInit; // temporary variable + DWORD dwLengthOut; // count of the decoded bytes + BYTE byLgCarry; // count of used bits in the carry + BYTE byLgByte; // count of used bits in the decoded byte + + /*----------------------------- + | Find the 1st flag. At the end + | of the loop dwShift is the count + | of bits to reach the 1st bit + | of the 1st flag. + +-----------------------------*/ + dwInit = *pbyBuffIn | (*(pbyBuffIn+1)<<8) | (*(pbyBuffIn+2)<<16); + for (byShift=0;byShift<17;byShift++) + { + if (!(((dwInit>>byShift)&0xFF)^0x7E)) + { + break; + } + } + + /*----------------------------- + | If at the end of the previous + | loop dwShift = 17, it means + | that no flag was found in the + | first 3 bytes (normally + | impossible impossible with the + | DSP algorithm) + +-----------------------------*/ + if (byShift == 17) + return 0; + + /*----------------------------- + | Plase the array pointer after + | the first flag. Update the + | shift. + +-----------------------------*/ + pbyBuffIn += byShift/8 + 1; + dwLength -= byShift/8 + 1; + byShift %= 8; + + /*----------------------------- + | Walk through the frame to + | find the first data byte + +-----------------------------*/ + dwInit = *pbyBuffIn | (*(pbyBuffIn+1)<<8); + while (!(((dwInit>>byShift)&0xFF)^0x7E)) + { + pbyBuffIn ++; + dwLength --; + dwInit = *pbyBuffIn | (*(pbyBuffIn+1)<<8); + } + + dwLengthOut = 0; + byCarry = 0; + byLgCarry = 0; + byLgByte = 0; + + /*------------------------------- + | Treat the first byte + +-------------------------------*/ + byCharIn = (*pbyBuffIn >> byShift) << byShift; + woInfo = destuffs[0][byCharIn]; + byLgByte = ((woInfo & 0x7000) >> 12) + 1; + woNb1 = (woInfo & 0x0F00) >> 8; + dwLength --; + pbyBuffIn++; + + if (woNb1 > 5) + return 0; + + if (byLgByte - byShift == 8) + { + *pbyBuffOut ++ = woInfo; + dwLengthOut ++; + } + else + { + byCarry = woInfo << (8 - byLgByte); + byLgCarry = byLgByte - byShift; + } + + /*------------------------------- + | main loop + +-------------------------------*/ + while(dwLength --) + { + byCharIn = *pbyBuffIn ++; + + woInfo = destuffs[woNb1][byCharIn]; + byLgByte = ((woInfo & 0x7000) >> 12) + 1; + + /*------------------------------- + | if the used bits in the carry + | and the current byte makes + | possible to output a full byte + +-------------------------------*/ + if (byLgByte + byLgCarry >= 8) + { + *pbyBuffOut ++ = ( (woInfo << 8) | byCarry) >> (8 - byLgCarry); + dwLengthOut ++; + byLgCarry += byLgByte - 8; + byCarry = woInfo << (8-byLgByte); + } + /*------------------------------- + | if the used bits in the carry + | and the current byte doesn't + | make possible to output a full + | byte + +-------------------------------*/ + else + { + dwInit = (woInfo << 8) | byCarry; + byLgCarry += byLgByte; + byCarry = dwInit >> byLgByte; + } + + woNb1 = (woInfo & 0x0F00) >> 8; + + /*------------------------------- + | if the current byte contains + | six or more consecutive '1' + +-------------------------------*/ + if (woInfo & 0x8000) + { + byCarry = ((byCharIn << 8) | *(pbyBuffIn-2)) >> (8 - byLgCarry); + if (byCarry == 0x7E) + return dwLengthOut-1; + else + if (woNb1 > 6) + return 0; + else + if ((!(*pbyBuffIn & 1)) && (byLgCarry == 7)) + return dwLengthOut; + else + return 0; + } + } + + return dwLengthOut; +} + diff --git a/drivers/isdn/tpam/tpam_main.c b/drivers/isdn/tpam/tpam_main.c new file mode 100644 index 000000000000..b0714e41391f --- /dev/null +++ b/drivers/isdn/tpam/tpam_main.c @@ -0,0 +1,289 @@ +/* $Id: tpam_main.c,v 1.1.2.1 2001/06/05 19:45:37 kai Exp $ + * + * Turbo PAM ISDN driver for Linux. (Kernel Driver - main routines) + * + * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * For all support questions please contact: <support@auvertech.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/tqueue.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <asm/io.h> + +#include "tpam.h" + +/* Local functions prototypes */ +static int __devinit tpam_probe(struct pci_dev *, const struct pci_device_id *); +static void __devexit tpam_unregister_card(tpam_card *); +static void __devexit tpam_remove(struct pci_dev *); +static int __init tpam_init(void); +static void __exit tpam_exit(void); + +/* List of boards */ +static tpam_card *cards; /* = NULL; */ +/* Number of cards */ +static int cards_num; +/* Configurable id of the driver */ +static char *id = "tpam\0\0\0\0\0\0\0\0\0\0\0\0"; + +MODULE_DESCRIPTION("Driver for TurboPAM cards"); +MODULE_AUTHOR("Stelian Pop, Alcove"); +MODULE_SUPPORTED_DEVICE("ISDN subsystem"); +MODULE_PARM_DESC(id,"ID-String of the driver"); +MODULE_PARM(id,"s"); + +/* + * Finds a board by its driver ID. + * + * driverId: driver ID (as referenced by the IDSN link layer) + * + * Return: the tpam_card structure if found, NULL on error. + */ +tpam_card *tpam_findcard(int driverid) { + tpam_card *p = cards; + + while (p) { + if (p->id == driverid) + return p; + p = p->next; + } + return NULL; +} + +/* + * Finds a channel number by its ncoid. + * + * card: the board + * ncoid: the NCO id + * + * Return: the channel number if found, TPAM_CHANNEL_INVALID if not. + */ +u32 tpam_findchannel(tpam_card *card, u32 ncoid) { + int i; + + for (i = 0; i < TPAM_NBCHANNEL; ++i) + if (card->channels[i].ncoid == ncoid) + return card->channels[i].num; + return TPAM_CHANNEL_INVALID; +} + +/* + * Initializes and registers a new TurboPAM card. + * + * dev: the PCI device + * num: the board number + * + * Return: 0 if OK, <0 if error + */ +static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { + tpam_card *card, *c; + int i; + + /* allocate memory for the board structure */ + if (!(card = (tpam_card *)kmalloc(sizeof(tpam_card), GFP_KERNEL))) { + printk(KERN_ERR "TurboPAM: tpam_register_card: " + "kmalloc failed!\n"); + return -ENOMEM; + } + + memset((char *)card, 0, sizeof(tpam_card)); + + card->irq = dev->irq; + card->lock = SPIN_LOCK_UNLOCKED; + sprintf(card->interface.id, "%s%d", id, cards_num); + + /* request interrupt */ + if (request_irq(card->irq, &tpam_irq, SA_INTERRUPT | SA_SHIRQ, + card->interface.id, card)) { + printk(KERN_ERR "TurboPAM: tpam_register_card: " + "could not request irq %d\n", card->irq); + kfree(card); + return -EIO; + } + + /* remap board memory */ + if (!(card->bar0 = (unsigned long) ioremap(pci_resource_start(dev, 0), + 0x800000))) { + printk(KERN_ERR "TurboPAM: tpam_register_card: " + "unable to remap bar0\n"); + free_irq(card->irq, card); + kfree(card); + return -EIO; + } + + /* reset the board */ + readl(card->bar0 + TPAM_RESETPAM_REGISTER); + + /* initialisation magic :-( */ + copy_to_pam_dword(card, (void *)0x01800008, 0x00000030); + copy_to_pam_dword(card, (void *)0x01800010, 0x00000030); + copy_to_pam_dword(card, (void *)0x01800014, 0x42240822); + copy_to_pam_dword(card, (void *)0x01800018, 0x07114000); + copy_to_pam_dword(card, (void *)0x0180001c, 0x00000400); + copy_to_pam_dword(card, (void *)0x01840070, 0x00000010); + + /* fill the ISDN link layer structure */ + card->interface.channels = TPAM_NBCHANNEL; + card->interface.maxbufsize = TPAM_MAXBUFSIZE; + card->interface.features = + ISDN_FEATURE_P_EURO | + ISDN_FEATURE_L2_HDLC | + ISDN_FEATURE_L2_MODEM; + card->interface.hl_hdrlen = 0; + card->interface.command = tpam_command; + card->interface.writebuf_skb = tpam_writebuf_skb; + card->interface.writecmd = NULL; + card->interface.readstat = NULL; + + /* register wrt the ISDN link layer */ + if (!register_isdn(&card->interface)) { + printk(KERN_ERR "TurboPAM: tpam_register_card: " + "unable to register %s\n", card->interface.id); + free_irq(card->irq, card); + iounmap((void *)card->bar0); + kfree(card); + return -EIO; + } + card->id = card->interface.channels; + + /* initialize all channels */ + for (i = 0; i < TPAM_NBCHANNEL; ++i) { + card->channels[i].num = i; + card->channels[i].card = card; + card->channels[i].ncoid = TPAM_NCOID_INVALID; + card->channels[i].hdlc = 0; + card->channels[i].realhdlc = 0; + card->channels[i].hdlcshift = 0; + skb_queue_head_init(&card->channels[i].sendq); + } + + /* initialize the rest of board structure */ + card->channels_used = 0; + card->channels_tested = 0; + card->running = 0; + card->busy = 0; + card->roundrobin = 0; + card->loopmode = 0; + skb_queue_head_init(&card->sendq); + skb_queue_head_init(&card->recvq); + card->recv_tq.routine = (void *) (void *) tpam_recv_tq; + card->recv_tq.data = card; + card->send_tq.routine = (void *) (void *) tpam_send_tq; + card->send_tq.data = card; + + /* add the board at the end of the list of boards */ + card->next = NULL; + if (cards) { + c = cards; + while (c->next) + c = c->next; + c->next = card; + } + else + cards = card; + + ++cards_num; + pci_set_drvdata(dev, card); + + return 0; +} + +/* + * Unregisters a TurboPAM board by releasing all its ressources (irq, mem etc). + * + * card: the board. + */ +static void __devexit tpam_unregister_card(tpam_card *card) { + isdn_ctrl cmd; + + /* prevent the ISDN link layer that the driver will be unloaded */ + cmd.command = ISDN_STAT_UNLOAD; + cmd.driver = card->id; + (* card->interface.statcallb)(&cmd); + + /* release interrupt */ + free_irq(card->irq, card); + + /* release mapped memory */ + iounmap((void *)card->bar0); +} + +/* + * Stops the driver. + */ +static void __devexit tpam_remove(struct pci_dev *pcidev) { + tpam_card *card = pci_get_drvdata(pcidev); + tpam_card *c; + + /* remove from the list of cards */ + if (card == cards) + cards = cards->next; + else { + c = cards; + while (c->next != card) + c = c->next; + c->next = c->next->next; + } + + /* unregister each board */ + tpam_unregister_card(card); + + /* and free the board structure itself */ + kfree(card); +} + +static struct pci_device_id tpam_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_TURBOPAM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(pci, tpam_pci_tbl); + +static struct pci_driver tpam_driver = { + name: "tpam", + id_table: tpam_pci_tbl, + probe: tpam_probe, + remove: tpam_remove, +}; + +static int __init tpam_init(void) { + int ret; + + ret = pci_module_init(&tpam_driver); + if (ret) + return ret; + printk(KERN_INFO "TurboPAM: %d card%s found, driver loaded.\n", + cards_num, (cards_num > 1) ? "s" : ""); + return 0; +} + +static void __exit tpam_exit(void) { + pci_unregister_driver(&tpam_driver); + printk(KERN_INFO "TurboPAM: driver unloaded\n"); +} + +/* Module entry points */ +module_init(tpam_init); +module_exit(tpam_exit); + diff --git a/drivers/isdn/tpam/tpam_memory.c b/drivers/isdn/tpam/tpam_memory.c new file mode 100644 index 000000000000..253ebfb82eae --- /dev/null +++ b/drivers/isdn/tpam/tpam_memory.c @@ -0,0 +1,258 @@ +/* $Id: tpam_memory.c,v 1.1.2.1 2001/06/05 19:45:37 kai Exp $ + * + * Turbo PAM ISDN driver for Linux. (Kernel Driver - Board Memory Access) + * + * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * For all support questions please contact: <support@auvertech.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include <linux/config.h> +#include <linux/pci.h> +#include <asm/io.h> + +#include "tpam.h" + +/* + * Write a DWORD into the board memory. + * + * card: the board + * addr: the address (in the board memory) + * val: the value to put into the memory. + */ +void copy_to_pam_dword(tpam_card *card, const void *addr, u32 val) { + + /* set the page register */ + writel(((unsigned long)addr) | TPAM_PAGE_SIZE, + card->bar0 + TPAM_PAGE_REGISTER); + + /* write the value */ + writel(val, card->bar0 + (((u32)addr) & TPAM_PAGE_SIZE)); +} + +/* + * Write n bytes into the board memory. The count of bytes will be rounded + * up to a multiple of 4. + * + * card: the board + * to: the destination address (in the board memory) + * from: the source address (in the kernel memory) + * n: number of bytes + */ +void copy_to_pam(tpam_card *card, void *to, const void *from, u32 n) { + u32 page, offset, count; + + /* need to write in dword ! */ + while (n & 3) n++; + + while (n) { + page = ((u32)to) | TPAM_PAGE_SIZE; + offset = ((u32)to) & TPAM_PAGE_SIZE; + count = n < TPAM_PAGE_SIZE - offset + ? n + : TPAM_PAGE_SIZE - offset; + + /* set the page register */ + writel(page, card->bar0 + TPAM_PAGE_REGISTER); + + /* copy the data */ + memcpy_toio((void *)(card->bar0 + offset), from, count); + + from += count; + to += count; + n -= count; + } +} + +/* + * Read a DWORD from the board memory. + * + * card: the board + * addr: the address (in the board memory) + * + * Return: the value read into the memory. + */ +u32 copy_from_pam_dword(tpam_card *card, const void *addr) { + + /* set the page register */ + writel(((u32)addr) | TPAM_PAGE_SIZE, + card->bar0 + TPAM_PAGE_REGISTER); + + /* read the data */ + return readl(card->bar0 + (((u32)addr) & TPAM_PAGE_SIZE)); +} + +/* + * Read n bytes from the board memory. + * + * card: the board + * to: the destination address (in the kernel memory) + * from: the source address (in the board memory) + * n: number of bytes + */ +void copy_from_pam(tpam_card *card, void *to, const void *from, u32 n) { + u32 page, offset, count; + + while (n) { + page = ((u32)from) | TPAM_PAGE_SIZE; + offset = ((u32)from) & TPAM_PAGE_SIZE; + count = n < TPAM_PAGE_SIZE - offset + ? n + : TPAM_PAGE_SIZE - offset; + + /* set the page register */ + writel(page, card->bar0 + TPAM_PAGE_REGISTER); + + /* read the data */ + memcpy_fromio(to, (void *)(card->bar0 + offset), count); + + from += count; + to += count; + n -= count; + } +} + +/* + * Read n bytes from the board memory and writes them into the user memory. + * + * card: the board + * to: the destination address (in the userspace memory) + * from: the source address (in the board memory) + * n: number of bytes + * + * Return: 0 if OK, <0 if error. + */ +int copy_from_pam_to_user(tpam_card *card, void *to, const void *from, u32 n) { + void *page; + u32 count; + + /* allocate a free page for the data transfer */ + if (!(page = (void *)__get_free_page(GFP_KERNEL))) { + printk(KERN_ERR "TurboPAM(copy_from_pam_to_user): " + "get_free_page failed\n"); + return -ENOMEM; + } + + while (n) { + count = n < PAGE_SIZE ? n : PAGE_SIZE; + + /* copy data from the board into the kernel memory */ + spin_lock_irq(&card->lock); + copy_from_pam(card, page, from, count); + spin_unlock_irq(&card->lock); + + /* copy it from the kernel memory into the user memory */ + if (copy_to_user(to, page, count)) { + + /* this can fail... */ + free_page((u32)page); + return -EFAULT; + } + from += count; + to += count; + n -= count; + } + + /* release allocated memory */ + free_page((u32)page); + return 0; +} + +/* + * Read n bytes from the user memory and writes them into the board memory. + * + * card: the board + * to: the destination address (in the board memory) + * from: the source address (in the userspace memory) + * n: number of bytes + * + * Return: 0 if OK, <0 if error. + */ +int copy_from_user_to_pam(tpam_card *card, void *to, const void *from, u32 n) { + void *page; + u32 count; + + /* allocate a free page for the data transfer */ + if (!(page = (void *)__get_free_page(GFP_KERNEL))) { + printk(KERN_ERR "TurboPAM(copy_from_user_to_pam): " + "get_free_page failed\n"); + return -ENOMEM; + } + + while (n) { + count = n < PAGE_SIZE ? n : PAGE_SIZE; + + /* copy data from the user memory into the kernel memory */ + if (copy_from_user(page, from, count)) { + /* this can fail... */ + free_page((u32)page); + return -EFAULT; + } + + /* copy it from the kernel memory into the board memory */ + spin_lock_irq(&card->lock); + copy_to_pam(card, to, page, count); + spin_unlock_irq(&card->lock); + + from += count; + to += count; + n -= count; + } + + /* release allocated memory */ + free_page((u32)page); + return 0; +} + +/* + * Verify if we have the permission to read or writes len bytes at the + * address address from/to the board memory. + * + * address: the start address (in the board memory) + * len: number of bytes + * + * Return: 0 if OK, <0 if error. + */ +int tpam_verify_area(u32 address, u32 len) { + + if (address < TPAM_RESERVEDAREA1_START) + return (address + len <= TPAM_RESERVEDAREA1_START) ? 0 : -1; + + if (address <= TPAM_RESERVEDAREA1_END) + return -1; + + if (address < TPAM_RESERVEDAREA2_START) + return (address + len <= TPAM_RESERVEDAREA2_START) ? 0 : -1; + + if (address <= TPAM_RESERVEDAREA2_END) + return -1; + + if (address < TPAM_RESERVEDAREA3_START) + return (address + len <= TPAM_RESERVEDAREA3_START) ? 0 : -1; + + if (address <= TPAM_RESERVEDAREA3_END) + return -1; + + if (address < TPAM_RESERVEDAREA4_START) + return (address + len <= TPAM_RESERVEDAREA4_START) ? 0 : -1; + + if (address <= TPAM_RESERVEDAREA4_END) + return -1; + + return 0; +} + diff --git a/drivers/isdn/tpam/tpam_nco.c b/drivers/isdn/tpam/tpam_nco.c new file mode 100644 index 000000000000..20dc732ee206 --- /dev/null +++ b/drivers/isdn/tpam/tpam_nco.c @@ -0,0 +1,662 @@ +/* $Id: tpam_nco.c,v 1.1.2.1 2001/06/05 19:45:37 kai Exp $ + * + * Turbo PAM ISDN driver for Linux. (Kernel Driver - Low Level NCO Manipulation) + * + * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * For all support questions please contact: <support@auvertech.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include <linux/config.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/tqueue.h> +#include <linux/interrupt.h> +#include <asm/io.h> + +#include "tpam.h" + +/* Local function prototypes */ +static struct sk_buff *build_NCOpacket(u16, u16, u16, u16, u16); +static int extract_NCOParameter(struct sk_buff *, u8, void *, u16); + +/* + * Build a NCO packet (PCI message). + * + * messageID: the message type (ID_*) + * size: size of the TLV block + * data_size: size of the data block + * ack: packet needs to send ack upon send + * ack_size: size of data to be acknowledged upon send + * + * Return: the sk_buff filled with the NCO packet, or NULL if error. + */ +static struct sk_buff *build_NCOpacket(u16 messageID, u16 size, + u16 data_size, u16 ack, + u16 ack_size) { + struct sk_buff *skb; + skb_header *h; + pci_mpb *p; + u16 finalsize; + + /* reserve enough space for the sk_buff header, the pci * header, + * size bytes for the TLV block, size bytes for the data and 4 more + * bytes in order to make sure we can write dwords to the board. */ + finalsize = sizeof(skb_header) + sizeof(pci_mpb) + size + data_size + 4; + + /* allocate the sk_buff */ + if (!(skb = alloc_skb(finalsize, GFP_ATOMIC))) { + printk(KERN_ERR "TurboPAM(make_NCOpacket): alloc_skb failed\n"); + return NULL; + } + + /* construct the skb_header */ + h = (skb_header *)skb_put(skb, sizeof(skb_header)); + h->size = sizeof(pci_mpb) + size; + h->data_size = data_size; + h->ack = ack; + h->ack_size = ack_size; + + /* construct the pci_mpb */ + p = (pci_mpb *)skb_put(skb, sizeof(pci_mpb)); + p->exID = 0; + p->flags = 0; + p->errorCode = 0; + p->messageID = messageID; + p->maximumBlockTLVSize = MPB_MAXIMUMBLOCKTLVSIZE; + p->actualBlockTLVSize = size; + p->maximumDataSize = MPB_MAXIMUMDATASIZE; + p->actualDataSize = data_size; + return skb; +} + +/* + * Build a ACreateNCOReq message. + * + * phone: the local phone number. + * + * Return: the sk_buff filled with the NCO packet, or NULL if error. + */ +struct sk_buff *build_ACreateNCOReq(const u8 *phone) { + struct sk_buff *skb; + u8 *tlv; + + dprintk("TurboPAM(build_ACreateNCOReq): phone=%s\n", phone); + + /* build the NCO packet */ + if (!(skb = build_NCOpacket(ID_ACreateNCOReq, 23 + strlen(phone), 0, 0, 0))) + return NULL; + + /* add the parameters */ + tlv = (u8 *)skb_put(skb, 3); + *tlv = PAR_NCOType; + *(tlv+1) = 1; + *(tlv+2) = 5; /* mistery value... */ + + tlv = (u8 *)skb_put(skb, 4); + *tlv = PAR_U3Protocol; + *(tlv+1) = 2; + *(tlv+2) = 4; /* no level 3 protocol */ + *(tlv+3) = 1; /* HDLC in level 2 */ + + tlv = (u8 *)skb_put(skb, 3); + *tlv = PAR_Cdirection; + *(tlv+1) = 1; + *(tlv+2) = 3; /* PCI_DIRECTION_BOTH */ + + tlv = (u8 *)skb_put(skb, 3); + *tlv = PAR_Udirection; + *(tlv+1) = 1; + *(tlv+2) = 3; /* PCI_DIRECTION_BOTH */ + + tlv = (u8 *)skb_put(skb, 4); + *tlv = PAR_BearerCap; + *(tlv+1) = 2; + *(tlv+2) = 0x88; + *(tlv+3) = 0x90; + + tlv = (u8 *)skb_put(skb, 6 + strlen(phone)); + *tlv = PAR_CallingNumber; + *(tlv+1) = strlen(phone) + 4; + *(tlv+2) = 0x01; /* international */ + *(tlv+3) = 0x01; /* isdn */ + *(tlv+4) = 0x00; + *(tlv+5) = 0x00; + memcpy(tlv + 6, phone, strlen(phone)); + + return skb; +} + +/* + * Build a ADestroyNCOReq message. + * + * ncoid: the NCO id. + * + * Return: the sk_buff filled with the NCO packet, or NULL if error. + */ +struct sk_buff *build_ADestroyNCOReq(u32 ncoid) { + struct sk_buff *skb; + u8 *tlv; + + dprintk("TurboPAM(build_ADestroyNCOReq): ncoid=%lu\n", + (unsigned long)ncoid); + + /* build the NCO packet */ + if (!(skb = build_NCOpacket(ID_ADestroyNCOReq, 6, 0, 0, 0))) + return NULL; + + /* add the parameters */ + tlv = (u8 *)skb_put(skb, 6); + *tlv = PAR_NCOID; + *(tlv+1) = 4; + *((u32 *)(tlv+2)) = ncoid; + + return skb; +} + +/* + * Build a CConnectReq message. + * + * ncoid: the NCO id. + * called: the destination phone number + * hdlc: type of connection: 1 (HDLC) or 0(modem) + * + * Return: the sk_buff filled with the NCO packet, or NULL if error. + */ +struct sk_buff *build_CConnectReq(u32 ncoid, const u8 *called, u8 hdlc) { + struct sk_buff *skb; + u8 *tlv; + + dprintk("TurboPAM(build_CConnectReq): ncoid=%lu, called=%s, hdlc=%d\n", + (unsigned long)ncoid, called, hdlc); + + /* build the NCO packet */ + if (!(skb = build_NCOpacket(ID_CConnectReq, 20 + strlen(called), 0, 0, 0))) + return NULL; + + /* add the parameters */ + tlv = (u8 *)skb_put(skb, 6); + *tlv = PAR_NCOID; + *(tlv+1) = 4; + *((u32 *)(tlv+2)) = ncoid; + + tlv = (u8 *)skb_put(skb, 4 + strlen(called)); + *tlv = PAR_CalledNumber; + *(tlv+1) = strlen(called) + 2; + *(tlv+2) = 0x01; /* international */ + *(tlv+3) = 0x01; /* isdn */ + memcpy(tlv + 4, called, strlen(called)); + + tlv = (u8 *)skb_put(skb, 3); + *tlv = PAR_BearerCap; + *(tlv+1) = 1; + *(tlv+2) = hdlc ? 0x88 /* HDLC */ : 0x80 /* MODEM */; + + tlv = (u8 *)skb_put(skb, 4); + *tlv = PAR_HLC; + *(tlv+1) = 2; + *(tlv+2) = 0x2; + *(tlv+3) = 0x7f; + + tlv = (u8 *)skb_put(skb, 3); + *tlv = PAR_Facility; + *(tlv+1) = 1; + *(tlv+2) = 2; + + return skb; +} + +/* + * Build a CConnectRsp message. + * + * ncoid: the NCO id. + * + * Return: the sk_buff filled with the NCO packet, or NULL if error. + */ +struct sk_buff *build_CConnectRsp(u32 ncoid) { + struct sk_buff *skb; + u8 *tlv; + + dprintk("TurboPAM(build_CConnectRsp): ncoid=%lu\n", + (unsigned long)ncoid); + + /* build the NCO packet */ + if (!(skb = build_NCOpacket(ID_CConnectRsp, 6, 0, 0, 0))) + return NULL; + + /* add the parameters */ + tlv = (u8 *)skb_put(skb, 6); + *tlv = PAR_NCOID; + *(tlv+1) = 4; + *((u32 *)(tlv+2)) = ncoid; + + return skb; +} + +/* + * Build a CDisconnectReq message. + * + * ncoid: the NCO id. + * + * Return: the sk_buff filled with the NCO packet, or NULL if error. + */ +struct sk_buff *build_CDisconnectReq(u32 ncoid) { + struct sk_buff *skb; + u8 *tlv; + + dprintk("TurboPAM(build_CDisconnectReq): ncoid=%lu\n", + (unsigned long)ncoid); + + /* build the NCO packet */ + if (!(skb = build_NCOpacket(ID_CDisconnectReq, 6, 0, 0, 0))) + return NULL; + + /* add the parameters */ + tlv = (u8 *)skb_put(skb, 6); + *tlv = PAR_NCOID; + *(tlv+1) = 4; + *((u32 *)(tlv+2)) = ncoid; + + return skb; +} + +/* + * Build a CDisconnectRsp message. + * + * ncoid: the NCO id. + * + * Return: the sk_buff filled with the NCO packet, or NULL if error. + */ +struct sk_buff *build_CDisconnectRsp(u32 ncoid) { + struct sk_buff *skb; + u8 *tlv; + + dprintk("TurboPAM(build_CDisconnectRsp): ncoid=%lu\n", + (unsigned long)ncoid); + + /* build the NCO packet */ + if (!(skb = build_NCOpacket(ID_CDisconnectRsp, 6, 0, 0, 0))) + return NULL; + + /* add the parameters */ + tlv = (u8 *)skb_put(skb, 6); + *tlv = PAR_NCOID; + *(tlv+1) = 4; + *((u32 *)(tlv+2)) = ncoid; + + return skb; +} + +/* + * Build a U3DataReq message. + * + * ncoid: the NCO id. + * data: the data to be send + * len: length of the data + * ack: send ack upon send + * ack_size: size of data to be acknowledged upon send + * + * Return: the sk_buff filled with the NCO packet, or NULL if error. + */ +struct sk_buff *build_U3DataReq(u32 ncoid, void *data, u16 len, + u16 ack, u16 ack_size) { + struct sk_buff *skb; + u8 *tlv; + void *p; + + dprintk("TurboPAM(build_U3DataReq): " + "ncoid=%lu, len=%d, ack=%d, ack_size=%d\n", + (unsigned long)ncoid, len, ack, ack_size); + + /* build the NCO packet */ + if (!(skb = build_NCOpacket(ID_U3DataReq, 6, len, ack, ack_size))) + return NULL; + + /* add the parameters */ + tlv = (u8 *)skb_put(skb, 6); + *tlv = PAR_NCOID; + *(tlv+1) = 4; + *((u32 *)(tlv+2)) = ncoid; + + p = skb_put(skb, len); + memcpy(p, data, len); + + return skb; +} + +/* + * Extract a parameter from a TLV block. + * + * skb: sk_buff containing the PCI message + * type: parameter to search for (PARAM_*) + * value: to be filled with the value of the parameter + * len: maximum length of the parameter value + * + * Return: 0 if OK, <0 if error. + */ +static int extract_NCOParameter(struct sk_buff *skb, u8 type, + void *value, u16 len) { + void *buffer = (void *)skb->data; + pci_mpb *p; + void * bufferend; + u8 valtype; + u16 vallen; + + /* calculate the start and end of the TLV block */ + buffer += sizeof(skb_header); + p = (pci_mpb *)buffer; + buffer += sizeof(pci_mpb); + bufferend = buffer + p->actualBlockTLVSize; + + /* walk through the parameters */ + while (buffer < bufferend) { + + /* parameter type */ + valtype = *((u8 *)buffer++); + /* parameter length */ + vallen = *((u8 *)buffer++); + if (vallen == 0xff) { + /* parameter length is on 2 bytes */ + vallen = *((u8 *)buffer++); + vallen <<= 8; + vallen |= *((u8 *)buffer++); + } + /* got the right parameter */ + if (valtype == type) { + /* not enough space for returning the value */ + if (vallen > len) + return -1; + /* OK, return it */ + memcpy(value, buffer, vallen); + return 0; + } + buffer += vallen; + } + return -1; +} + +/* + * Parse a ACreateNCOCnf message. + * + * skb: the sk_buff containing the message + * status: to be filled with the status field value + * ncoid: to be filled with the ncoid field value + * + * Return: 0 if OK, <0 if error. + */ +int parse_ACreateNCOCnf(struct sk_buff *skb, u8 *status, u32 *ncoid) { + + /* extract the status */ + if (extract_NCOParameter(skb, PAR_CompletionStatus, status, 1)) { + printk(KERN_ERR "TurboPAM(parse_ACreateNCOCnf): " + "CompletionStatus not found\n"); + return -1; + } + + if (*status) { + dprintk("TurboPAM(parse_ACreateNCOCnf): status=%d\n", *status); + return 0; + } + + /* extract the ncoid */ + if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) { + printk(KERN_ERR "TurboPAM(parse_ACreateNCOCnf): " + "NCOID not found\n"); + return -1; + } + + dprintk("TurboPAM(parse_ACreateNCOCnf): ncoid=%lu, status=%d\n", + (unsigned long)*ncoid, *status); + return 0; +} + +/* + * Parse a ADestroyNCOCnf message. Not used in the driver. + * + * skb: the sk_buff containing the message + * status: to be filled with the status field value + * ncoid: to be filled with the ncoid field value + * + * Return: 0 if OK, <0 if error. + */ +int parse_ADestroyNCOCnf(struct sk_buff *skb, u8 *status, u32 *ncoid) { + + /* extract the status */ + if (extract_NCOParameter(skb, PAR_CompletionStatus, status, 1)) { + printk(KERN_ERR "TurboPAM(parse_ADestroyNCOCnf): " + "CompletionStatus not found\n"); + return -1; + } + + if (*status) { + dprintk("TurboPAM(parse_ADestroyNCOCnf): status=%d\n", *status); + return 0; + } + + /* extract the ncoid */ + if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) { + printk(KERN_ERR "TurboPAM(parse_ADestroyNCOCnf): " + "NCOID not found\n"); + return -1; + } + + dprintk("TurboPAM(parse_ADestroyNCOCnf): ncoid=%lu, status=%d\n", + (unsigned long)*ncoid, *status); + return 0; +} + +/* + * Parse a CConnectCnf message. + * + * skb: the sk_buff containing the message + * ncoid: to be filled with the ncoid field value + * + * Return: 0 if OK, <0 if error. + */ +int parse_CConnectCnf(struct sk_buff *skb, u32 *ncoid) { + + /* extract the ncoid */ + if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) { + printk(KERN_ERR "TurboPAM(parse_CConnectCnf): " + "NCOID not found\n"); + return -1; + } + dprintk("TurboPAM(parse_CConnectCnf): ncoid=%lu\n", + (unsigned long)*ncoid); + return 0; +} + +/* + * Parse a CConnectInd message. + * + * skb: the sk_buff containing the message + * ncoid: to be filled with the ncoid field value + * hdlc: to be filled with 1 if the incoming connection is a HDLC one, + * with 0 if the incoming connection is a modem one + * calling: to be filled with the calling phone number value + * called: to be filled with the called phone number value + * plan: to be filled with the plan value + * screen: to be filled with the screen value + * + * Return: 0 if OK, <0 if error. + */ +int parse_CConnectInd(struct sk_buff *skb, u32 *ncoid, u8 *hdlc, + u8 *calling, u8 *called, u8 *plan, u8 *screen) { + u8 phone[PHONE_MAXIMUMSIZE + 4]; + + /* extract the ncoid */ + if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) { + printk(KERN_ERR "TurboPAM(parse_CConnectInd): " + "NCOID not found\n"); + return -1; + } + + /* extract the bearer capability field */ + if (extract_NCOParameter(skb, PAR_BearerCap, hdlc, 1)) { + printk(KERN_ERR "TurboPAM(parse_CConnectInd): " + "BearerCap not found\n"); + return -1; + } + *hdlc = (*hdlc == 0x88) ? 1 : 0; + + /* extract the calling number / plan / screen */ + if (extract_NCOParameter(skb, PAR_CallingNumber, phone, + PHONE_MAXIMUMSIZE + 4)) { + printk(KERN_ERR "TurboPAM(parse_CConnectInd): " + "CallingNumber not found\n"); + return -1; + } + memcpy(calling, phone + 4, PHONE_MAXIMUMSIZE); + *plan = phone[1]; + *screen = phone[3]; + + /* extract the called number */ + if (extract_NCOParameter(skb, PAR_CalledNumber, phone, + PHONE_MAXIMUMSIZE + 2)) { + printk(KERN_ERR "TurboPAM(parse_CConnectInd): " + "CalledNumber not found\n"); + return -1; + } + memcpy(called, phone + 2, PHONE_MAXIMUMSIZE); + + dprintk("TurboPAM(parse_CConnectInd): " + "ncoid=%lu, hdlc=%d, plan=%d, scr=%d, calling=%s, called=%s\n", + (unsigned long)*ncoid, *hdlc, *plan, *screen, calling, called); + return 0; +} + +/* + * Parse a CDisconnectCnf message. + * + * skb: the sk_buff containing the message + * ncoid: to be filled with the ncoid field value + * causetopuf: to be filled with the cause field value + * + * Return: 0 if OK, <0 if error. + */ +int parse_CDisconnectCnf(struct sk_buff *skb, u32 *ncoid, u32 *causetopuf) { + + /* extract the ncoid */ + if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) { + printk(KERN_ERR "TurboPAM(parse_CDisconnectCnf): " + "NCOID not found\n"); + return -1; + } + + /* extract the cause of disconnection */ + if (extract_NCOParameter(skb, PAR_CauseToPUF, causetopuf, 4)) { + printk(KERN_ERR "TurboPAM(parse_CDisconnectCnf): " + "CauseToPUF not found\n"); + return -1; + } + + dprintk("TurboPAM(parse_CDisconnectCnf): ncoid=%lu, causetopuf=%lu\n", + (unsigned long)*ncoid, (unsigned long)*causetopuf); + return 0; +} + +/* + * Parse a CDisconnectInd message. + * + * skb: the sk_buff containing the message + * ncoid: to be filled with the ncoid field value + * causetopuf: to be filled with the cause field value + * + * Return: 0 if OK, <0 if error. + */ +int parse_CDisconnectInd(struct sk_buff *skb, u32 *ncoid, u32 *causetopuf) { + + /* extract the ncoid */ + if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) { + printk(KERN_ERR "TurboPAM(parse_CDisconnectInd): " + "NCOID not found\n"); + return -1; + } + + /* extract the cause of disconnection */ + if (extract_NCOParameter(skb, PAR_CauseToPUF, causetopuf, 4)) { + printk(KERN_ERR "TurboPAM(parse_CDisconnectInd): " + "CauseToPUF not found\n"); + return -1; + } + + dprintk("TurboPAM(parse_CDisconnectInd): ncoid=%lu, causetopuf=%lu\n", + (unsigned long)*ncoid, (unsigned long)*causetopuf); + return 0; +} + +/* + * Parse a U3ReadyToReceiveInd message. + * + * skb: the sk_buff containing the message + * ncoid: to be filled with the ncoid field value + * ready: to be filled with the ready field value + * + * Return: 0 if OK, <0 if error. + */ +int parse_U3ReadyToReceiveInd(struct sk_buff *skb, u32 *ncoid, u8 *ready) { + + /* extract the ncoid */ + if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) { + printk(KERN_ERR "TurboPAM(parse_U3ReadyToReceiveInd): " + "NCOID not found\n"); + return -1; + } + + /* extract the ready flag */ + if (extract_NCOParameter(skb, PAR_ReadyFlag, ready, 1)) { + printk(KERN_ERR "TurboPAM(parse_U3ReadyToReceiveInd): " + "ReadyFlag not found\n"); + return -1; + } + + dprintk("TurboPAM(parse_U3ReadyToReceiveInd): ncoid=%lu, ready=%d\n", + (unsigned long)*ncoid, *ready); + return 0; +} + +/* + * Parse a U3DataInd message. + * + * skb: the sk_buff containing the message + data + * ncoid: to be filled with the ncoid field value + * data: to be filled with the data + * ready: to be filled with the data length + * + * Return: 0 if OK, <0 if error. + */ +int parse_U3DataInd(struct sk_buff *skb, u32 *ncoid, u8 **data, u16 *len) { + pci_mpb *p; + + /* extract the ncoid */ + if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4) == -1) { + printk(KERN_ERR "TurboPAM(parse_U3DataInd): NCOID not found\n"); + return -1; + } + + /* get a pointer to the beginning of the data block and its length */ + p = (pci_mpb *)(skb->data + sizeof(skb_header)); + *len = p->actualDataSize; + skb_pull(skb, + sizeof(skb_header) + sizeof(pci_mpb) + p->actualBlockTLVSize); + *data = skb->data; + + dprintk("TurboPAM(parse_U3DataInd): ncoid=%lu, datalen=%d\n", + (unsigned long)*ncoid, *len); + return 0; +} + diff --git a/drivers/isdn/tpam/tpam_queues.c b/drivers/isdn/tpam/tpam_queues.c new file mode 100644 index 000000000000..15ec08a357e5 --- /dev/null +++ b/drivers/isdn/tpam/tpam_queues.c @@ -0,0 +1,418 @@ +/* $Id: tpam_queues.c,v 1.1.2.1 2001/06/05 19:45:37 kai Exp $ + * + * Turbo PAM ISDN driver for Linux. (Kernel Driver) + * + * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * For all support questions please contact: <support@auvertech.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/tqueue.h> +#include <linux/interrupt.h> +#include <asm/io.h> + +#include "tpam.h" + +/* Local function prototype */ +static int tpam_sendpacket(tpam_card *card, tpam_channel *channel); + +/* + * Queue a message to be send to the card when possible. + * + * card: the board + * skb: the sk_buff containing the message. + */ +void tpam_enqueue(tpam_card *card, struct sk_buff *skb) { + + dprintk("TurboPAM(tpam_enqueue): card=%d\n", card->id); + + /* queue the sk_buff on the board's send queue */ + skb_queue_tail(&card->sendq, skb); + + /* queue the board's send task struct for immediate treatment */ + queue_task(&card->send_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/* + * Queue a data message to be send to the card when possible. + * + * card: the board + * skb: the sk_buff containing the message and the data. This parameter + * can be NULL if we want just to trigger the send of queued + * messages. + */ +void tpam_enqueue_data(tpam_channel *channel, struct sk_buff *skb) { + + dprintk("TurboPAM(tpam_enqueue_data): card=%d, channel=%d\n", + channel->card->id, channel->num); + + /* if existant, queue the sk_buff on the channel's send queue */ + if (skb) + skb_queue_tail(&channel->sendq, skb); + + /* queue the channel's send task struct for immediate treatment */ + queue_task(&channel->card->send_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/* + * IRQ handler. + * + * If a message comes from the board we read it, construct a sk_buff containing + * the message and we queue the sk_buff on the board's receive queue, and we + * trigger the execution of the board's receive task queue. + * + * If a message ack comes from the board we can go on and send a new message, + * so we trigger the execution of the board's send task queue. + * + * irq: the irq number + * dev_id: the registered board to the irq + * regs: not used. + */ +void tpam_irq(int irq, void *dev_id, struct pt_regs *regs) { + tpam_card *card = (tpam_card *)dev_id; + u32 ackupload, uploadptr; + u32 waiting_too_long; + u32 hpic; + struct sk_buff *skb; + pci_mpb mpb; + skb_header *skbh; + + dprintk("TurboPAM(tpam_irq): IRQ received, card=%d\n", card->id); + + /* grab the board lock */ + spin_lock(&card->lock); + + /* get the message type */ + ackupload = copy_from_pam_dword(card, (void *)TPAM_ACKUPLOAD_REGISTER); + + /* acknowledge the interrupt */ + copy_to_pam_dword(card, (void *)TPAM_INTERRUPTACK_REGISTER, 0); + readl(card->bar0 + TPAM_HINTACK_REGISTER); + + if (!ackupload) { + /* it is a new message from the board */ + + dprintk("TurboPAM(tpam_irq): message received, card=%d\n", + card->id); + + /* get the upload pointer */ + uploadptr = copy_from_pam_dword(card, + (void *)TPAM_UPLOADPTR_REGISTER); + + /* get the beginning of the message (pci_mpb part) */ + copy_from_pam(card, &mpb, (void *)uploadptr, sizeof(pci_mpb)); + + /* allocate the sk_buff */ + if (!(skb = alloc_skb(sizeof(skb_header) + sizeof(pci_mpb) + + mpb.actualBlockTLVSize + + mpb.actualDataSize, GFP_ATOMIC))) { + printk(KERN_ERR "TurboPAM(tpam_irq): " + "alloc_skb failed\n"); + spin_unlock(&card->lock); + return; + } + + /* build the skb_header */ + skbh = (skb_header *)skb_put(skb, sizeof(skb_header)); + skbh->size = sizeof(pci_mpb) + mpb.actualBlockTLVSize; + skbh->data_size = mpb.actualDataSize; + skbh->ack = 0; + skbh->ack_size = 0; + + /* copy the pci_mpb into the sk_buff */ + memcpy(skb_put(skb, sizeof(pci_mpb)), &mpb, sizeof(pci_mpb)); + + /* copy the TLV block into the sk_buff */ + copy_from_pam(card, skb_put(skb, mpb.actualBlockTLVSize), + (void *)uploadptr + sizeof(pci_mpb), + mpb.actualBlockTLVSize); + + /* if existent, copy the data block into the sk_buff */ + if (mpb.actualDataSize) + copy_from_pam(card, skb_put(skb, mpb.actualDataSize), + (void *)uploadptr + sizeof(pci_mpb) + 4096, + mpb.actualDataSize); + + /* wait for the board to become ready */ + waiting_too_long = 0; + do { + hpic = readl(card->bar0 + TPAM_HPIC_REGISTER); + if (waiting_too_long++ > 0xfffffff) { + spin_unlock(&card->lock); + printk(KERN_ERR "TurboPAM(tpam_irq): " + "waiting too long...\n"); + return; + } + } while (hpic & 0x00000002); + + /* acknowledge the message */ + copy_to_pam_dword(card, (void *)TPAM_ACKDOWNLOAD_REGISTER, + 0xffffffff); + readl(card->bar0 + TPAM_DSPINT_REGISTER); + + /* release the board lock */ + spin_unlock(&card->lock); + + if (mpb.messageID == ID_U3ReadyToReceiveInd) { + /* this message needs immediate treatment */ + tpam_recv_U3ReadyToReceiveInd(card, skb); + kfree_skb(skb); + } + else { + /* put the message in the receive queue */ + skb_queue_tail(&card->recvq, skb); + queue_task(&card->recv_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + return; + } + else { + /* it is a ack from the board */ + + dprintk("TurboPAM(tpam_irq): message acknowledged, card=%d\n", + card->id); + + /* board is not busy anymore */ + card->busy = 0; + + /* release the lock */ + spin_unlock(&card->lock); + + /* schedule the send queue for execution */ + queue_task(&card->send_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return; + } + + /* not reached */ +} + +/* + * Run the board's receive task queue, dispatching each message on the queue, + * to its treatment function. + * + * card: the board. + */ +void tpam_recv_tq(tpam_card *card) { + pci_mpb *p; + struct sk_buff *skb; + + /* for each message on the receive queue... */ + while ((skb = skb_dequeue(&card->recvq))) { + + /* point to the pci_mpb block */ + p = (pci_mpb *)(skb->data + sizeof(skb_header)); + + /* dispatch the message */ + switch (p->messageID) { + case ID_ACreateNCOCnf: + tpam_recv_ACreateNCOCnf(card, skb); + break; + case ID_ADestroyNCOCnf: + tpam_recv_ADestroyNCOCnf(card, skb); + break; + case ID_CConnectCnf: + tpam_recv_CConnectCnf(card, skb); + break; + case ID_CConnectInd: + tpam_recv_CConnectInd(card, skb); + break; + case ID_CDisconnectInd: + tpam_recv_CDisconnectInd(card, skb); + break; + case ID_CDisconnectCnf: + tpam_recv_CDisconnectCnf(card, skb); + break; + case ID_U3DataInd: + tpam_recv_U3DataInd(card, skb); + break; + default: + dprintk("TurboPAM(tpam_recv_tq): " + "unknown messageID %d, card=%d\n", + p->messageID, card->id); + break; + } + /* free the sk_buff */ + kfree_skb(skb); + } +} + +/* + * Run the board's send task queue. If there is a message in the board's send + * queue, it gets sended. If not, it examines each channel (one at the time, + * using a round robin algorithm). For each channel, if there is a message + * in the channel's send queue, it gets sended. This function sends only one + * message, it does not consume all the queue. + */ +void tpam_send_tq(tpam_card *card) { + int i; + + /* first, try to send a packet from the board's send queue */ + if (tpam_sendpacket(card, NULL)) + return; + + /* then, try each channel, in a round-robin manner */ + for (i=card->roundrobin; i<card->roundrobin+card->channels_used; i++) { + if (tpam_sendpacket(card, + &card->channels[i % card->channels_used])) { + card->roundrobin = (i + 1) % card->channels_used; + return; + } + } +} + +/* + * Try to send a packet from the board's send queue or from the channel's + * send queue. + * + * card: the board. + * channel: the channel (if NULL, the packet will be taken from the + * board's send queue. If not, it will be taken from the + * channel's send queue. + * + * Return: 0 if tpam_send_tq must try another card/channel combination + * (meaning that no packet has been send), 1 if no more packets + * can be send at that time (a packet has been send or the card is + * still busy from a previous send). + */ +static int tpam_sendpacket(tpam_card *card, tpam_channel *channel) { + struct sk_buff *skb; + u32 hpic; + u32 downloadptr; + skb_header *skbh; + u32 waiting_too_long; + + dprintk("TurboPAM(tpam_sendpacket), card=%d, channel=%d\n", + card->id, channel ? channel->num : -1); + + if (channel) { + /* dequeue a packet from the channel's send queue */ + if (!(skb = skb_dequeue(&channel->sendq))) { + dprintk("TurboPAM(tpam_sendpacket): " + "card=%d, channel=%d, no packet\n", + card->id, channel->num); + return 0; + } + + /* if the channel is not ready to receive, requeue the packet + * and return 0 to give a chance to another channel */ + if (!channel->readytoreceive) { + dprintk("TurboPAM(tpam_sendpacket): " + "card=%d, channel=%d, channel not ready\n", + card->id, channel->num); + skb_queue_head(&channel->sendq, skb); + return 0; + } + + /* grab the board lock */ + spin_lock_irq(&card->lock); + + /* if the board is busy, requeue the packet and return 1 since + * there is no need to try another channel */ + if (card->busy) { + dprintk("TurboPAM(tpam_sendpacket): " + "card=%d, channel=%d, card busy\n", + card->id, channel->num); + skb_queue_head(&channel->sendq, skb); + spin_unlock_irq(&card->lock); + return 1; + } + } + else { + /* dequeue a packet from the board's send queue */ + if (!(skb = skb_dequeue(&card->sendq))) { + dprintk("TurboPAM(tpam_sendpacket): " + "card=%d, no packet\n", card->id); + return 0; + } + + /* grab the board lock */ + spin_lock_irq(&card->lock); + + /* if the board is busy, requeue the packet and return 1 since + * there is no need to try another channel */ + if (card->busy) { + dprintk("TurboPAM(tpam_sendpacket): " + "card=%d, card busy\n", card->id); + skb_queue_head(&card->sendq, skb); + spin_unlock_irq(&card->lock); + return 1; + } + } + + /* wait for the board to become ready */ + waiting_too_long = 0; + do { + hpic = readl(card->bar0 + TPAM_HPIC_REGISTER); + if (waiting_too_long++ > 0xfffffff) { + spin_unlock_irq(&card->lock); + printk(KERN_ERR "TurboPAM(tpam_sendpacket): " + "waiting too long...\n"); + return 1; + } + } while (hpic & 0x00000002); + + skbh = (skb_header *)skb->data; + dprintk("TurboPAM(tpam_sendpacket): " + "card=%d, card ready, sending %d/%d bytes\n", + card->id, skbh->size, skbh->data_size); + + /* get the board's download pointer */ + downloadptr = copy_from_pam_dword(card, + (void *)TPAM_DOWNLOADPTR_REGISTER); + + /* copy the packet to the board at the downloadptr location */ + copy_to_pam(card, (void *)downloadptr, skb->data + sizeof(skb_header), + skbh->size); + if (skbh->data_size) + /* if there is some data in the packet, copy it too */ + copy_to_pam(card, (void *)downloadptr + sizeof(pci_mpb) + 4096, + skb->data + sizeof(skb_header) + skbh->size, + skbh->data_size); + + /* card will become busy right now */ + card->busy = 1; + + /* interrupt the board */ + copy_to_pam_dword(card, (void *)TPAM_ACKDOWNLOAD_REGISTER, 0); + readl(card->bar0 + TPAM_DSPINT_REGISTER); + + /* release the lock */ + spin_unlock_irq(&card->lock); + + /* if a data ack was requested by the ISDN link layer, send it now */ + if (skbh->ack) { + isdn_ctrl ctrl; + ctrl.driver = card->id; + ctrl.command = ISDN_STAT_BSENT; + ctrl.arg = channel->num; + ctrl.parm.length = skbh->ack_size; + (* card->interface.statcallb)(&ctrl); + } + + /* free the sk_buff */ + kfree_skb(skb); + + return 1; +} + diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index fe92e94014f9..6e7cff42614d 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -1431,7 +1431,7 @@ int __openfirmware powerbook_sleep_G3(void) _set_L2CR(save_l2cr); /* Restore userland MMU context */ - set_context(current->mm->context, current->mm->pgd); + set_context(current->mm->context); /* Re-enable DEC interrupts and kick DEC */ asm volatile("mtdec %0" : : "r" (0x7fffffff)); @@ -1560,7 +1560,7 @@ int __openfirmware powerbook_sleep_Core99(void) feature_wake_up(); pbook_pci_restore(); - set_context(current->mm->context, current->mm->pgd); + set_context(current->mm->context); /* Restore L2 cache */ if (save_l2cr) diff --git a/drivers/md/md.c b/drivers/md/md.c index c81c475c3eac..765fe73d3577 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -483,14 +483,17 @@ static void free_disk_sb (mdk_rdev_t * rdev) } } -static void mark_rdev_faulty (mdk_rdev_t * rdev) +static inline int mark_rdev_faulty (mdk_rdev_t * rdev) { if (!rdev) { MD_BUG(); - return; + return 0; } + if (rdev->faulty) + return 0; free_disk_sb(rdev); rdev->faulty = 1; + return 1; } static int read_disk_sb (mdk_rdev_t * rdev) @@ -1645,8 +1648,7 @@ static int do_md_run (mddev_t * mddev) ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->faulty) continue; - fsync_dev(rdev->dev); - invalidate_buffers(rdev->dev); + invalidate_device(rdev->dev, 1); if (get_hardsect_size(rdev->dev) > md_hardsect_sizes[mdidx(mddev)]) md_hardsect_sizes[mdidx(mddev)] = @@ -1672,7 +1674,8 @@ static int do_md_run (mddev_t * mddev) * twice as large as sectors. */ md_hd_struct[mdidx(mddev)].start_sect = 0; - md_hd_struct[mdidx(mddev)].nr_sects = md_size[mdidx(mddev)] << 1; + register_disk(&md_gendisk, MKDEV(MAJOR_NR,mdidx(mddev)), + 1, &md_fops, md_size[mdidx(mddev)]<<1); read_ahead[MD_MAJOR] = 1024; return (0); @@ -1729,12 +1732,6 @@ static int do_md_stop (mddev_t * mddev, int ro) printk(STILL_IN_USE, mdidx(mddev)); OUT(-EBUSY); } - - /* this shouldn't be needed as above would have fired */ - if (!ro && is_mounted(dev)) { - printk (STILL_MOUNTED, mdidx(mddev)); - OUT(-EBUSY); - } if (mddev->pers) { /* @@ -1758,15 +1755,7 @@ static int do_md_stop (mddev_t * mddev, int ro) down(&mddev->recovery_sem); up(&mddev->recovery_sem); - /* - * sync and invalidate buffers because we cannot kill the - * main thread with valid IO transfers still around. - * the kernel lock protects us from new requests being - * added after invalidate_buffers(). - */ - fsync_dev (mddev_to_kdev(mddev)); - fsync_dev (dev); - invalidate_buffers (dev); + invalidate_device(dev, 1); if (ro) { if (mddev->ro) @@ -2946,7 +2935,8 @@ int md_error (mddev_t *mddev, kdev_t rdev) return 0; } rrdev = find_rdev(mddev, rdev); - mark_rdev_faulty(rrdev); + if (!mark_rdev_faulty(rrdev)) + return 0; /* * if recovery was running, stop it now. */ @@ -3228,7 +3218,6 @@ int md_do_sync(mddev_t *mddev, mdp_disk_t *spare) mddev_t *mddev2; unsigned int max_sectors, currspeed, j, window, err, serialize; - kdev_t read_disk = mddev_to_kdev(mddev); unsigned long mark[SYNC_MARKS]; unsigned long mark_cnt[SYNC_MARKS]; int last_mark,m; @@ -3361,7 +3350,6 @@ repeat: } else current->nice = -20; } - fsync_dev(read_disk); printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev)); err = 0; /* @@ -3507,7 +3495,6 @@ static void md_geninit (void) md_size[i] = 0; md_hardsect_sizes[i] = 512; md_maxreadahead[i] = MD_READAHEAD; - register_disk(&md_gendisk, MKDEV(MAJOR_NR,i), 1, &md_fops, 0); } blksize_size[MAJOR_NR] = md_blocksizes; blk_size[MAJOR_NR] = md_size; diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 9adf2eb87949..1d09e9da0c0a 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -178,7 +178,13 @@ /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1512 effectively disables this feature. */ +#ifndef __arm__ static const int rx_copybreak = 200; +#else +/* ARM systems perform better by disregarding the bus-master + transfer capability of these cards. -- rmk */ +static const int rx_copybreak = 1513; +#endif /* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */ static const int mtu = 1500; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ @@ -218,6 +224,7 @@ static int vortex_debug = 1; #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/pci.h> +#include <linux/mii.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -2646,26 +2653,32 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; int phy = vp->phys[0] & 0x1f; int retval; switch(cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = phy; - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = phy; + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ EL3WINDOW(4); - data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); retval = 0; break; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) { retval = -EPERM; } else { EL3WINDOW(4); - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); retval = 0; } break; diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index d9e8407c3315..f06e5bb34708 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -137,7 +137,7 @@ an MMIO register read. */ #define DRV_NAME "8139too" -#define DRV_VERSION "0.9.18-pre3" +#define DRV_VERSION "0.9.18-pre4" #include <linux/config.h> @@ -613,7 +613,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, static void rtl8139_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static int rtl8139_close (struct net_device *dev); -static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static struct net_device_stats *rtl8139_get_stats (struct net_device *dev); static inline u32 ether_crc (int length, unsigned char *data); static void rtl8139_set_rx_mode (struct net_device *dev); @@ -955,7 +955,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, dev->stop = rtl8139_close; dev->get_stats = rtl8139_get_stats; dev->set_multicast_list = rtl8139_set_rx_mode; - dev->do_ioctl = mii_ioctl; + dev->do_ioctl = netdev_ioctl; dev->tx_timeout = rtl8139_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -1699,17 +1699,14 @@ static void rtl8139_tx_timeout (struct net_device *dev) } - static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) { struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; unsigned int entry; - unsigned long flags; + u32 dma_addr; - /* XXX paranoid + sledgehammer == temporary system crash fix */ - wmb(); - spin_lock_irqsave (&tp->lock, flags); + mb(); /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; @@ -1721,28 +1718,29 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) if ((long) skb->data & 3) { /* Must use alignment buffer. */ /* tp->tx_info[entry].mapping = 0; */ memcpy (tp->tx_buf[entry], skb->data, skb->len); - RTL_W32_F (TxAddr0 + (entry * 4), - tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs)); + dma_addr = tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs); } else { tp->xstats.tx_buf_mapped++; tp->tx_info[entry].mapping = pci_map_single (tp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); - RTL_W32_F (TxAddr0 + (entry * 4), tp->tx_info[entry].mapping); + dma_addr = tp->tx_info[entry].mapping; } /* Note: the chip doesn't have auto-pad! */ - RTL_W32 (TxStatus0 + (entry * sizeof (u32)), - tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); + spin_lock_irq(&tp->lock); + RTL_W32_F (TxAddr0 + (entry * 4), dma_addr); + RTL_W32_F (TxStatus0 + (entry * sizeof (u32)), + tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); + spin_unlock_irq(&tp->lock); dev->trans_start = jiffies; tp->cur_tx++; + mb(); if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) netif_stop_queue (dev); - spin_unlock_irqrestore (&tp->lock, flags); - DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", dev->name, skb->data, skb->len, entry); @@ -1779,7 +1777,7 @@ static void rtl8139_tx_interrupt (struct net_device *dev, tp->stats.tx_errors++; if (txstatus & TxAborted) { tp->stats.tx_aborted_errors++; - RTL_W32_F (TxConfig, TxClearAbt); + RTL_W32_F (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift)); } if (txstatus & TxCarrierLost) tp->stats.tx_carrier_errors++; @@ -1814,7 +1812,6 @@ static void rtl8139_tx_interrupt (struct net_device *dev, dirty_tx++; tx_left--; - barrier(); } #ifndef RTL8139_NDEBUG @@ -1828,6 +1825,7 @@ static void rtl8139_tx_interrupt (struct net_device *dev, /* only wake the queue if we did work, and the queue is stopped */ if (tp->dirty_tx != dirty_tx) { tp->dirty_tx = dirty_tx; + mb(); if (netif_queue_stopped (dev)) netif_wake_queue (dev); } @@ -1908,6 +1906,8 @@ static void rtl8139_rx_interrupt (struct net_device *dev, unsigned int pkt_size; struct sk_buff *skb; + rmb(); + /* read size+status of next frame from DMA ring buffer */ rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); rx_size = rx_status >> 16; @@ -2057,6 +2057,8 @@ static void rtl8139_interrupt (int irq, void *dev_instance, int ackstat, status; int link_changed = 0; /* avoid bogus "uninit" warning */ + spin_lock (&tp->lock); + do { status = RTL_R16 (IntrStatus); @@ -2092,11 +2094,8 @@ static void rtl8139_interrupt (int irq, void *dev_instance, rtl8139_weird_interrupt (dev, tp, ioaddr, status, link_changed); - if (netif_running (dev) && (status & (TxOK | TxErr))) { - spin_lock (&tp->lock); + if (netif_running (dev) && (status & (TxOK | TxErr))) rtl8139_tx_interrupt (dev, tp, ioaddr); - spin_unlock (&tp->lock); - } boguscnt--; } while (boguscnt > 0); @@ -2109,6 +2108,8 @@ static void rtl8139_interrupt (int irq, void *dev_instance, RTL_W16 (IntrStatus, 0xffff); } + spin_unlock (&tp->lock); + DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, RTL_R16 (IntrStatus)); } @@ -2174,32 +2175,69 @@ static int rtl8139_close (struct net_device *dev) } -static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + struct rtl8139_private *np = dev->priv; + u32 ethcmd; + + if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: + { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + strcpy (info.bus_info, np->pci_dev->slot_name); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + + default: + break; + } + + return -EOPNOTSUPP; +} + +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { struct rtl8139_private *tp = dev->priv; - u16 *data = (u16 *) & rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; int rc = 0; + int phy = tp->phys[0] & 0x3f; DPRINTK ("ENTER\n"); + data->phy_id &= 0x1f; + data->reg_num &= 0x1f; + switch (cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = tp->phys[0] & 0x3f; + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + + case SIOCGMIIPHY: /* Get the address of the PHY in use. */ + case SIOCDEVPRIVATE: /* binary compat, remove in 2.5 */ + data->phy_id = phy; /* Fall Through */ - case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */ - data[3] = mdio_read (dev, data[0], data[1] & 0x1f); + case SIOCGMIIREG: /* Read the specified MII register. */ + case SIOCDEVPRIVATE+1: /* binary compat, remove in 2.5 */ + data->val_out = mdio_read (dev, data->phy_id, data->reg_num); break; - case SIOCDEVPRIVATE + 2: /* Write the specified MII register */ + case SIOCSMIIREG: /* Write the specified MII register */ + case SIOCDEVPRIVATE+2: /* binary compat, remove in 2.5 */ if (!capable (CAP_NET_ADMIN)) { rc = -EPERM; break; } - if (data[0] == tp->phys[0]) { - u16 value = data[2]; - switch (data[1]) { + if (data->phy_id == phy) { + u16 value = data->val_in; + switch (data->reg_num) { case 0: /* Check for autonegotiation on or reset. */ tp->medialock = (value & 0x9000) ? 0 : 1; @@ -2209,7 +2247,7 @@ static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) case 4: /* tp->advertising = value; */ break; } } - mdio_write(dev, data[0], data[1] & 0x1f, data[2]); + mdio_write(dev, data->phy_id, data->reg_num, data->val_in); break; default: diff --git a/drivers/net/Config.in b/drivers/net/Config.in index 0ac5827a2176..c8d15d27ec87 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -15,7 +15,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then fi fi -if [ "$CONFIG_ISAPNP" = "y" ]; then +if [ "$CONFIG_ISAPNP" = "y" -o "$CONFIG_ISAPNP" = "m" ]; then tristate 'General Instruments Surfboard 1000' CONFIG_NET_SB1000 $CONFIG_ISAPNP fi @@ -94,9 +94,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then dep_tristate ' WD80*3 support' CONFIG_WD80x3 $CONFIG_ISA dep_tristate ' SMC Ultra MCA support' CONFIG_ULTRAMCA $CONFIG_MCA - if [ "$CONFIG_ISA" = "y" -o "$CONFIG_ISAPNP" = "y" ]; then - tristate ' SMC Ultra support' CONFIG_ULTRA - fi + dep_tristate ' SMC Ultra support' CONFIG_ULTRA $CONFIG_ISA dep_tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32 $CONFIG_EISA dep_tristate ' SMC 9194 support' CONFIG_SMC9194 $CONFIG_ISA fi @@ -106,10 +104,8 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then dep_tristate ' NI5210 support' CONFIG_NI52 $CONFIG_ISA dep_tristate ' NI6510 support' CONFIG_NI65 $CONFIG_ISA fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then - tristate ' AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700 - fi + if [ "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then + dep_tristate ' AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700 $CONFIG_EXPERIMENTAL fi if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_MCA" = "y" ]; then tristate ' DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA @@ -142,7 +138,11 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then tristate ' NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA tristate ' IBM LAN Adapter/A support' CONFIG_IBMLANA fi - dep_bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI + if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" ]; then + bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI + else + define_bool CONFIG_NET_PCI n + fi if [ "$CONFIG_NET_PCI" = "y" ]; then dep_tristate ' AMD PCnet32 PCI support' CONFIG_PCNET32 $CONFIG_PCI dep_tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI $CONFIG_EXPERIMENTAL @@ -153,10 +153,8 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then dep_tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT $CONFIG_ISA dep_tristate ' CS89x0 support' CONFIG_CS89x0 $CONFIG_ISA dep_tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP $CONFIG_PCI - if [ "$CONFIG_TULIP" = "y" -o "$CONFIG_TULIP" = "m" ]; then - dep_bool ' New bus configuration (EXPERIMENTAL)' CONFIG_TULIP_MWI $CONFIG_EXPERIMENTAL - bool ' Use PCI shared mem for NIC registers' CONFIG_TULIP_MMIO - fi + dep_mbool ' New bus configuration (EXPERIMENTAL)' CONFIG_TULIP_MWI $CONFIG_EXPERIMENTAL $CONFIG_TULIP + dep_mbool ' Use PCI shared mem for NIC registers' CONFIG_TULIP_MMIO $CONFIG_TULIP if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS @@ -208,9 +206,7 @@ mainmenu_option next_comment comment 'Ethernet (1000 Mbit)' dep_tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC $CONFIG_PCI -if [ "$CONFIG_ACENIC" != "n" ]; then - bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I -fi +dep_mbool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I $CONFIG_ACENIC dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL @@ -248,9 +244,7 @@ if [ ! "$CONFIG_PPP" = "n" ]; then dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP - fi + dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP $CONFIG_EXPERIMENTAL fi tristate 'SLIP (serial line) support' CONFIG_SLIP diff --git a/drivers/net/aironet4500_proc.c b/drivers/net/aironet4500_proc.c index 22f3035f465d..60555bf262b2 100644 --- a/drivers/net/aironet4500_proc.c +++ b/drivers/net/aironet4500_proc.c @@ -1,5 +1,5 @@ /* - * Aironet 4500 Pcmcia driver + * Aironet 4500 /proc interface * * Elmer Joandi, Januar 1999 * Copyright GPL diff --git a/drivers/net/declance.c b/drivers/net/declance.c index ddd6cec9cf33..7a86e003c5c1 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -83,7 +83,7 @@ static char *lancestr = "LANCE"; #include <linux/etherdevice.h> #ifndef CONFIG_TC -unsigned long system_base = 0; +unsigned long system_base; unsigned long dmaptr; #endif static int type; diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 15398e5b0745..ff3864a962e9 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -2732,7 +2732,7 @@ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers) for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) { - struct sk_buff *newskb = __dev_alloc_skb(NEW_SKB_SIZE, GFP_NOFS); /* Why not GFP_KERNEL? */ + struct sk_buff *newskb = __dev_alloc_skb(NEW_SKB_SIZE, GFP_NOIO); if (!newskb) return -ENOMEM; bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | diff --git a/drivers/net/dmfe.c b/drivers/net/dmfe.c index d66e2b462cc7..541ee4497ae3 100644 --- a/drivers/net/dmfe.c +++ b/drivers/net/dmfe.c @@ -130,7 +130,7 @@ #define DMFE_TX_TIMEOUT (HZ * 1.5) /* tx packet time-out time 1.5 s" */ #define DMFE_TX_KICK (HZ * 0.5) /* tx packet Kick-out time 0.5 s" */ -#define DMFE_DBUG(dbug_now, msg, vaule) if (dmfe_debug || dbug_now) printk(KERN_ERR "<DMFE>: %s %x\n", msg, vaule) +#define DMFE_DBUG(dbug_now, msg, value) if (dmfe_debug || (dbug_now)) printk(KERN_ERR "<DMFE>: %s %lx\n", (msg), (long) (value)) #define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR "<DMFE>: Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half"); @@ -182,7 +182,7 @@ struct dmfe_board_info { struct pci_dev * net_dev; /* PCI device */ spinlock_t lock; - u32 ioaddr; /* I/O base address */ + long ioaddr; /* I/O base address */ u32 cr0_data; u32 cr5_data; u32 cr6_data; @@ -206,10 +206,10 @@ struct dmfe_board_info { struct rx_desc *first_rx_desc; struct rx_desc *rx_insert_ptr; struct rx_desc *rx_ready_ptr; /* packet come pointer */ - u32 tx_packet_cnt; /* transmitted packet count */ - u32 tx_queue_cnt; /* wait to send packet count */ - u32 rx_avail_cnt; /* available rx descriptor count */ - u32 interval_rx_cnt; /* rx packet count a callback time */ + unsigned long tx_packet_cnt; /* transmitted packet count */ + unsigned long tx_queue_cnt; /* wait to send packet count */ + unsigned long rx_avail_cnt; /* available rx descriptor count */ + unsigned long interval_rx_cnt; /* rx packet count a callback time */ u16 HPNA_command; /* For HPNA register 16 */ u16 HPNA_timer; /* For HPNA remote device check */ @@ -265,20 +265,20 @@ static int __devinitdata printed_version; static char version[] __devinitdata = KERN_INFO "Davicom DM9xxx net driver, version " DMFE_VERSION "\n"; -static int dmfe_debug = 0; +static int dmfe_debug; static unsigned char dmfe_media_mode = DMFE_AUTO; -static u32 dmfe_cr6_user_set = 0; +static u32 dmfe_cr6_user_set; /* For module input parameter */ -static int debug = 0; -static u32 cr6set = 0; +static int debug; +static u32 cr6set; static unsigned char mode = 8; static u8 chkmode = 1; -static u8 HPNA_mode = 0; /* Default: Low Power/High Speed */ -static u8 HPNA_rx_cmd = 0; /* Default: Disable Rx remote command */ -static u8 HPNA_tx_cmd = 0; /* Default: Don't issue remote command */ -static u8 HPNA_NoiseFloor = 0; /* Default: HPNA NoiseFloor */ -static u8 SF_mode = 0; /* Special Function: 1:VLAN, 2:RX Flow Control +static u8 HPNA_mode; /* Default: Low Power/High Speed */ +static u8 HPNA_rx_cmd; /* Default: Disable Rx remote command */ +static u8 HPNA_tx_cmd; /* Default: Don't issue remote command */ +static u8 HPNA_NoiseFloor; /* Default: HPNA NoiseFloor */ +static u8 SF_mode; /* Special Function: 1:VLAN, 2:RX Flow Control 4: TX pause packet */ unsigned long CrcTable[256] = { @@ -357,15 +357,15 @@ static void dmfe_set_filter_mode(struct DEVICE *); static int dmfe_do_ioctl(struct DEVICE *, struct ifreq *, int); static u16 read_srom_word(long ,int); static void dmfe_interrupt(int , void *, struct pt_regs *); -static void dmfe_descriptor_init(struct dmfe_board_info *, u32); +static void dmfe_descriptor_init(struct dmfe_board_info *, unsigned long); static void allocated_rx_buffer(struct dmfe_board_info *); -static void update_cr6(u32, u32); +static void update_cr6(u32, unsigned long); static void send_filter_frame(struct DEVICE * ,int); static void dm9132_id_table(struct DEVICE * ,int); -static u16 phy_read(u32, u8, u8, u32); -static void phy_write(u32, u8, u8, u16, u32); -static void phy_write_1bit(u32, u32); -static u16 phy_read_1bit(u32); +static u16 phy_read(unsigned long, u8, u8, u32); +static void phy_write(unsigned long, u8, u8, u16, u32); +static void phy_write_1bit(unsigned long, u32); +static u16 phy_read_1bit(unsigned long); static u8 dmfe_sense_speed(struct dmfe_board_info *); static void dmfe_process_mode(struct dmfe_board_info *); static void dmfe_timer(unsigned long); @@ -607,7 +607,7 @@ static int dmfe_open(struct DEVICE *dev) static void dmfe_init_dm910x(struct DEVICE *dev) { struct dmfe_board_info *db = dev->priv; - u32 ioaddr = db->ioaddr; + unsigned long ioaddr = db->ioaddr; DMFE_DBUG(0, "dmfe_init_dm910x()", 0); @@ -693,7 +693,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) /* No Tx resource check, it never happen nromally */ if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) { spin_unlock_irqrestore(&db->lock, flags); - printk(KERN_ERR "<DMFE>: No Tx resource %d\n", db->tx_queue_cnt); + printk(KERN_ERR "<DMFE>: No Tx resource %ld\n", db->tx_queue_cnt); return 1; } @@ -742,7 +742,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) static int dmfe_stop(struct DEVICE *dev) { struct dmfe_board_info *db = dev->priv; - u32 ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr; DMFE_DBUG(0, "dmfe_stop", 0); @@ -785,7 +785,7 @@ static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct DEVICE *dev = dev_id; struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv; - u32 ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr; unsigned long flags; DMFE_DBUG(0, "dmfe_interrupt()", 0); @@ -851,7 +851,7 @@ static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs) static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db) { struct tx_desc *txptr; - u32 ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr; txptr = db->tx_remove_ptr; while(db->tx_packet_cnt) { @@ -1275,7 +1275,7 @@ static void dmfe_reused_skb(struct dmfe_board_info *db, struct sk_buff * skb) * Using Chain structure, and allocated Tx/Rx buffer */ -static void dmfe_descriptor_init(struct dmfe_board_info *db, u32 ioaddr) +static void dmfe_descriptor_init(struct dmfe_board_info *db, unsigned long ioaddr) { struct tx_desc *tmp_tx; struct rx_desc *tmp_rx; @@ -1334,11 +1334,11 @@ static void dmfe_descriptor_init(struct dmfe_board_info *db, u32 ioaddr) /* - * Update CR6 vaule + * Update CR6 value * Firstly stop DM910X , then written value and start */ -static void update_cr6(u32 cr6_data, u32 ioaddr) +static void update_cr6(u32 cr6_data, unsigned long ioaddr) { u32 cr6_tmp; @@ -1359,7 +1359,7 @@ static void dm9132_id_table(struct DEVICE *dev, int mc_cnt) { struct dev_mc_list *mcptr; u16 * addrptr; - u32 ioaddr = dev->base_addr+0xc0; /* ID Table */ + unsigned long ioaddr = dev->base_addr+0xc0; /* ID Table */ u32 hash_val; u16 i, hash_table[4]; @@ -1470,7 +1470,7 @@ static void allocated_rx_buffer(struct dmfe_board_info *db) while(db->rx_avail_cnt < RX_DESC_CNT) { if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL ) break; - rxptr->rx_skb_ptr = (u32) skb; + rxptr->rx_skb_ptr = (u32) skb; /* FIXME */ rxptr->rdes2 = cpu_to_le32( pci_map_single(db->net_dev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); rxptr->rdes0 = cpu_to_le32(0x80000000); rxptr = (struct rx_desc *) rxptr->next_rx_desc; @@ -1663,10 +1663,10 @@ static void dmfe_process_mode(struct dmfe_board_info *db) * Write a word to Phy register */ -static void phy_write(u32 iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id) +static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id) { u16 i; - u32 ioaddr; + unsigned long ioaddr; if (chip_id == PCI_DM9132_ID) { ioaddr = iobase + 0x80 + offset * 4; @@ -1710,11 +1710,11 @@ static void phy_write(u32 iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip * Read a word data from phy register */ -static u16 phy_read(u32 iobase, u8 phy_addr, u8 offset, u32 chip_id) +static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id) { int i; u16 phy_data; - u32 ioaddr; + unsigned long ioaddr; if (chip_id == PCI_DM9132_ID) { /* DM9132 Chip */ @@ -1762,7 +1762,7 @@ static u16 phy_read(u32 iobase, u8 phy_addr, u8 offset, u32 chip_id) * Write one bit data to Phy Controller */ -static void phy_write_1bit(u32 ioaddr, u32 phy_data) +static void phy_write_1bit(unsigned long ioaddr, u32 phy_data) { outl(phy_data, ioaddr); /* MII Clock Low */ udelay(1); @@ -1777,7 +1777,7 @@ static void phy_write_1bit(u32 ioaddr, u32 phy_data) * Read one bit phy data from PHY controller */ -static u16 phy_read_1bit(u32 ioaddr) +static u16 phy_read_1bit(unsigned long ioaddr) { u16 phy_data; diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 1d974350cc77..ac9aab20555c 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -54,33 +54,32 @@ static int dummy_accept_fastpath(struct net_device *dev, struct dst_entry *dst) static int __init dummy_init(struct net_device *dev) { /* Initialize the device structure. */ - dev->hard_start_xmit = dummy_xmit; dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_device_stats)); - dev->get_stats = dummy_get_stats; + dev->get_stats = dummy_get_stats; + dev->hard_start_xmit = dummy_xmit; dev->set_multicast_list = set_multicast_list; +#ifdef CONFIG_NET_FASTROUTE + dev->accept_fastpath = dummy_accept_fastpath; +#endif - /* Fill in the fields of the device structure with ethernet-generic values. */ + /* Fill in device structure with ethernet-generic values. */ ether_setup(dev); dev->tx_queue_len = 0; dev->flags |= IFF_NOARP; dev->flags &= ~IFF_MULTICAST; -#ifdef CONFIG_NET_FASTROUTE - dev->accept_fastpath = dummy_accept_fastpath; -#endif return 0; } static int dummy_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_device_stats *stats; + struct net_device_stats *stats = dev->priv; - stats = (struct net_device_stats *)dev->priv; stats->tx_packets++; stats->tx_bytes+=skb->len; @@ -106,8 +105,9 @@ static int __init dummy_init_module(void) err=dev_alloc_name(&dev_dummy,"dummy%d"); if(err<0) return err; - if (register_netdev(&dev_dummy) != 0) - return -EIO; + err = register_netdev(&dev_dummy); + if (err<0) + return err; return 0; } diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index ccf5ed1ea37b..6cb131ecc438 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -43,7 +43,7 @@ static int rxdmacount /* = 0 */; /* Set the copy breakpoint for the copy-only-tiny-buffer Rx method. Lower values use more memory, but are faster. */ -#if defined(__alpha__) || defined(__sparc__) +#if defined(__alpha__) || defined(__sparc__) || defined(__arm__) static int rx_copybreak = 1518; #else static int rx_copybreak = 200; @@ -102,6 +102,7 @@ static int debug = -1; /* The debug level */ #include <linux/pci.h> #include <linux/spinlock.h> #include <linux/init.h> +#include <linux/mii.h> #include <asm/bitops.h> #include <asm/io.h> @@ -125,16 +126,16 @@ MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(multicast_filter_limit, "i"); MODULE_PARM_DESC(debug, "eepro100 debug level (0-6)"); -MODULE_PARM_DESC(options, "epro100: Bits 0-3: tranceiver type, bit 4: full duplex, bit 5: 100Mbps"); -MODULE_PARM_DESC(full_duplex, "epro100 full duplex setting(s) (1)"); -MODULE_PARM_DESC(congenb, "epro100 Enable congestion control (1)"); -MODULE_PARM_DESC(txfifo, "epro100 Tx FIFO threshold in 4 byte units, (0-15)"); -MODULE_PARM_DESC(rxfifo, "epro100 Rx FIFO threshold in 4 byte units, (0-15)"); -MODULE_PARM_DESC(txdmaccount, "epro100 Tx DMA burst length; 128 - disable (0-128)"); -MODULE_PARM_DESC(rxdmaccount, "epro100 Rx DMA burst length; 128 - disable (0-128)"); -MODULE_PARM_DESC(rx_copybreak, "epro100 copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(max_interrupt_work, "epro100 maximum events handled per interrupt"); -MODULE_PARM_DESC(multicast_filter_limit, "epro100 maximum number of filtered multicast addresses"); +MODULE_PARM_DESC(options, "eepro100: Bits 0-3: tranceiver type, bit 4: full duplex, bit 5: 100Mbps"); +MODULE_PARM_DESC(full_duplex, "eepro100 full duplex setting(s) (1)"); +MODULE_PARM_DESC(congenb, "eepro100 Enable congestion control (1)"); +MODULE_PARM_DESC(txfifo, "eepro100 Tx FIFO threshold in 4 byte units, (0-15)"); +MODULE_PARM_DESC(rxfifo, "eepro100 Rx FIFO threshold in 4 byte units, (0-15)"); +MODULE_PARM_DESC(txdmaccount, "eepro100 Tx DMA burst length; 128 - disable (0-128)"); +MODULE_PARM_DESC(rxdmaccount, "eepro100 Rx DMA burst length; 128 - disable (0-128)"); +MODULE_PARM_DESC(rx_copybreak, "eepro100 copy breakpoint for copy-only-tiny-frames"); +MODULE_PARM_DESC(max_interrupt_work, "eepro100 maximum events handled per interrupt"); +MODULE_PARM_DESC(multicast_filter_limit, "eepro100 maximum number of filtered multicast addresses"); #define RUN_AT(x) (jiffies + (x)) @@ -155,8 +156,6 @@ static inline int null_set_power_state(struct pci_dev *dev, int state) (dev)->tx_timeout = (tf); \ (dev)->watchdog_timeo = (tm); \ } while(0) -#define netif_device_attach(dev) netif_start_queue(dev) -#define netif_device_detach(dev) netif_stop_queue(dev) #ifndef PCI_DEVICE_ID_INTEL_ID1029 #define PCI_DEVICE_ID_INTEL_ID1029 0x1029 @@ -472,7 +471,6 @@ struct speedo_private { dma_addr_t last_rxf_dma; unsigned int cur_rx, dirty_rx; /* The next free ring entry */ long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ - const char *product_name; struct net_device_stats stats; struct speedo_stats *lstats; dma_addr_t lstats_dma; @@ -800,7 +798,7 @@ static int speedo_found1(struct pci_dev *pdev, /* Return the chip to its original power state. */ pci_set_power_state(pdev, acpi_idle_state); - pdev->driver_data = dev; + pci_set_drvdata (pdev, dev); dev->base_addr = ioaddr; dev->irq = pdev->irq; @@ -1906,32 +1904,37 @@ static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct speedo_private *sp = (struct speedo_private *)dev->priv; long ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; int phy = sp->phy[0] & 0x1f; int saved_acpi; int t; switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = phy; - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = phy; + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ /* FIXME: these operations need to be serialized with MDIO access from the timeout handler. They are currently serialized only with MDIO access from the timer routine. 2000/05/09 SAW */ saved_acpi = pci_set_power_state(sp->pdev, 0); t = del_timer_sync(&sp->timer); - data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f); if (t) add_timer(&sp->timer); /* may be set to the past --SAW */ pci_set_power_state(sp->pdev, saved_acpi); return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; saved_acpi = pci_set_power_state(sp->pdev, 0); t = del_timer_sync(&sp->timer); - mdio_write(ioaddr, data[0], data[1], data[2]); + mdio_write(ioaddr, data->phy_id, data->reg_num, data->val_in); if (t) add_timer(&sp->timer); /* may be set to the past --SAW */ pci_set_power_state(sp->pdev, saved_acpi); @@ -2143,9 +2146,12 @@ static void set_rx_mode(struct net_device *dev) #ifdef CONFIG_PM static int eepro100_suspend(struct pci_dev *pdev, u32 state) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); long ioaddr = dev->base_addr; + if (!netif_running(dev)) + return 0; + netif_device_detach(dev); outl(PortPartialReset, ioaddr + SCBPort); @@ -2155,10 +2161,13 @@ static int eepro100_suspend(struct pci_dev *pdev, u32 state) static int eepro100_resume(struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); struct speedo_private *sp = (struct speedo_private *)dev->priv; long ioaddr = dev->base_addr; + if (!netif_running(dev)) + return 0; + /* I'm absolutely uncertain if this part of code may work. The problems are: - correct hardware reinitialization; @@ -2178,7 +2187,7 @@ static int eepro100_resume(struct pci_dev *pdev) static void __devexit eepro100_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); struct speedo_private *sp = (struct speedo_private *)dev->priv; unregister_netdev(dev); diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 2330b8285349..e9cab7c10399 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -45,13 +45,16 @@ * { fill me in } LK1.1.8: - * ethtool support (jgarzik) + * ethtool driver info support (jgarzik) + + LK1.1.9: + * MII ioctl support (jgarzik) */ #define DRV_NAME "epic100" -#define DRV_VERSION "1.11+LK1.1.8" -#define DRV_RELDATE "May 18, 2001" +#define DRV_VERSION "1.11+LK1.1.9" +#define DRV_RELDATE "July 2, 2001" /* The user-configurable values. @@ -1351,27 +1354,30 @@ static void set_rx_mode(struct net_device *dev) return; } -static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) { struct epic_private *np = dev->priv; u32 ethcmd; - - if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + + if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd))) return -EFAULT; - switch (ethcmd) { - case ETHTOOL_GDRVINFO: { - struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; - strcpy(info.driver, DRV_NAME); - strcpy(info.version, DRV_VERSION); - strcpy(info.bus_info, np->pci_dev->slot_name); - if (copy_to_user(useraddr, &info, sizeof(info))) - return -EFAULT; - return 0; + switch (ethcmd) { + case ETHTOOL_GDRVINFO: + { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + strcpy (info.bus_info, np->pci_dev->slot_name); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + + default: + break; } - } - return -EOPNOTSUPP; } @@ -1379,20 +1385,24 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; switch(cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = ep->phys[0] & 0x1f; + + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = ep->phys[0] & 0x1f; /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ if (! netif_running(dev)) { outl(0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); } - data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); #if 0 /* Just leave on if the ioctl() is ever used. */ if (! netif_running(dev)) { outl(0x0008, ioaddr + GENCTL); @@ -1400,16 +1410,18 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } #endif return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; if (! netif_running(dev)) { outl(0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); } - if (data[0] == ep->phys[0]) { - u16 value = data[2]; - switch (data[1]) { + if (data->phy_id == ep->phys[0]) { + u16 value = data->val_in; + switch (data->reg_num) { case 0: /* Check for autonegotiation on or reset. */ ep->duplex_lock = (value & 0x9000) ? 0 : 1; @@ -1420,7 +1432,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } /* Perhaps check_duplex(dev), depending on chip semantics. */ } - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); #if 0 /* Leave on if the ioctl() is used. */ if (! netif_running(dev)) { outl(0x0008, ioaddr + GENCTL); diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 8e16c1b68c6e..4c3c2ce7c926 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -17,7 +17,7 @@ http://www.scyld.com/network/pci-skeleton.html */ -static int debug = 0; /* 1-> print debug message */ +static int debug; /* 1-> print debug message */ static int max_interrupt_work = 20; /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */ @@ -25,7 +25,7 @@ static int multicast_filter_limit = 32; /* Set the copy breakpoint for the copy-only-tiny-frames scheme. */ /* Setting to > 1518 effectively disables this feature. */ -static int rx_copybreak = 0; +static int rx_copybreak; /* Used to pass the media type, etc. */ /* Both 'options[]' and 'full_duplex[]' should exist for driver */ @@ -71,6 +71,7 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/init.h> +#include <linux/mii.h> #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/bitops.h> #include <asm/io.h> @@ -1742,19 +1743,24 @@ static void set_rx_mode(struct net_device *dev) static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - u16 *data = (u16 *) & rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; switch (cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = ((struct netdev_private *) dev->priv)->phys[0] & 0x1f; + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = ((struct netdev_private *) dev->priv)->phys[0] & 0x1f; /* Fall Through */ - case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */ - data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); return 0; - case SIOCDEVPRIVATE + 2: /* Write the specified MII register */ + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!suser()) return -EPERM; - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); return 0; default: return -EOPNOTSUPP; diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index c3bab07db104..1fea1b38ec04 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -164,6 +164,7 @@ static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; #include <linux/pci.h> #include <linux/init.h> #include <linux/ethtool.h> +#include <linux/mii.h> #include <asm/uaccess.h> #include <asm/processor.h> /* Processor type for cache alignment. */ @@ -1873,24 +1874,29 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { long ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; switch(cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = ((struct hamachi_private *)dev->priv)->phys[0] & 0x1f; + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = ((struct hamachi_private *)dev->priv)->phys[0] & 0x1f; /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f); return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ /* TODO: Check the sequencing of this. Might need to stop and * restart Rx and Tx engines. -KDU */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); return 0; case SIOCDEVPRIVATE+3: { /* set rx,tx intr params */ u32 *d = (u32 *)&rq->ifr_data; diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index d1051f953747..6392dfa21a4b 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -1515,13 +1515,13 @@ static char devicename[9] = {0,}; static struct net_device dev_82596 = { - devicename, /* device name inserted by drivers/net/net_init.c */ - 0, 0, 0, 0, - 0, 0, /* base, irq */ - 0, 0, 0, NULL, lasi_i82596_probe}; + name: devicename, /* device name inserted by drivers/net/net_init.c */ + init: lasi_i82596_probe, +}; MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "lasi_82596 debug mask"); static int debug = -1; int init_module(void) diff --git a/drivers/net/ncr885e.c b/drivers/net/ncr885e.c index 78152f4272ec..e380d9903d7e 100644 --- a/drivers/net/ncr885e.c +++ b/drivers/net/ncr885e.c @@ -60,7 +60,7 @@ static const char *chipname = "ncr885e"; #define EOP (1<<7) /* rx: end of packet written to buffer */ int ncr885e_debug = NCR885E_DEBUG; -static int print_version = 0; +static int print_version; struct ncr885e_private { @@ -94,7 +94,7 @@ struct ncr885e_private { spinlock_t lock; }; -static struct net_device *root_dev = NULL; +static struct net_device *root_dev; static int ncr885e_open( struct net_device *dev ); static int ncr885e_close( struct net_device *dev ); diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 24576f9eaa3c..09078e922d68 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -94,6 +94,7 @@ IVc. Errata #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/delay.h> +#include <linux/mii.h> #include <asm/io.h> #define NETDRV_VERSION "1.0.0" @@ -1782,31 +1783,34 @@ static int netdrv_close (struct net_device *dev) static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { struct netdrv_private *tp = dev->priv; - u16 *data = (u16 *) & rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; unsigned long flags; int rc = 0; DPRINTK ("ENTER\n"); switch (cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = tp->phys[0] & 0x3f; + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = tp->phys[0] & 0x3f; /* Fall Through */ - case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */ + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ spin_lock_irqsave (&tp->lock, flags); - data[3] = mdio_read (dev, data[0] & 0x1f, data[1] & 0x1f); + data->val_out = mdio_read (dev, data->phy_id & 0x1f, data->reg_num & 0x1f); spin_unlock_irqrestore (&tp->lock, flags); break; - case SIOCDEVPRIVATE + 2: /* Write the specified MII register */ + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable (CAP_NET_ADMIN)) { rc = -EPERM; break; } spin_lock_irqsave (&tp->lock, flags); - mdio_write (dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write (dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); spin_unlock_irqrestore (&tp->lock, flags); break; diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 93e9c996ca8f..fb21b3c663d8 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -47,6 +47,16 @@ static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken static unsigned int pcnet32_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360, 0}; +/* + * PCI device identifiers for "new style" Linux PCI Device Drivers + */ +static struct pci_device_id pcnet32_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000, 0, 0, 0 }, + { 0, } +}; + static int pcnet32_debug = 1; static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */ @@ -205,16 +215,6 @@ static int full_duplex[MAX_UNITS]; #define PCNET32_TOTAL_SIZE 0x20 -/* some PCI ids */ -#ifndef PCI_DEVICE_ID_AMD_LANCE -#define PCI_VENDOR_ID_AMD 0x1022 -#define PCI_DEVICE_ID_AMD_LANCE 0x2000 -#endif -#ifndef PCI_DEVICE_ID_AMD_PCNETHOME -#define PCI_DEVICE_ID_AMD_PCNETHOME 0x2001 -#endif - - #define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ /* The PCNET32 Rx and Tx ring descriptors. */ @@ -320,16 +320,6 @@ struct pcnet32_pci_id_info { }; -/* - * PCI device identifiers for "new style" Linux PCI Device Drivers - */ -static struct pci_device_id pcnet32_pci_tbl[] __devinitdata = { - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000, 0, 0, 0 }, - { 0, } -}; - MODULE_DEVICE_TABLE (pci, pcnet32_pci_tbl); static u16 pcnet32_wio_read_csr (unsigned long addr, int index) diff --git a/drivers/net/rcif.h b/drivers/net/rcif.h index a41f05aac20d..85ff8615ccfd 100644 --- a/drivers/net/rcif.h +++ b/drivers/net/rcif.h @@ -38,39 +38,35 @@ /* The following protocol revision # should be incremented every time a new protocol or new structures are used in this file. */ -int USER_PROTOCOL_REV = 2; /* used to track different protocol revisions */ +int USER_PROTOCOL_REV = 2; /* used to track different protocol revisions */ /* define a single TCB & buffer */ -typedef struct /* a single buffer */ -{ - U32 context; /* context */ - U32 scount; /* segment count */ - U32 size; /* segment size */ - U32 addr; /* segment physical address */ -} -__attribute__((packed)) -singleB, *psingleB ; -typedef struct /* a single TCB */ -{ - /* - ** +-----------------------+ - ** | 1 | one buffer in the TCB - ** +-----------------------+ - ** | <user's Context> | user's buffer reference - ** +-----------------------+ - ** | 1 | one segment buffer - ** +-----------------------+ _ - ** | <buffer size> | size \ - ** +-----------------------+ \ segment descriptor - ** | <physical address> | physical address of buffer / - ** +-----------------------+ _/ - */ - U32 bcount; /* buffer count */ - singleB b; /* buffer */ - -} -__attribute__((packed)) -singleTCB, *psingleTCB; +typedef struct { /* a single buffer */ + U32 context; /* context */ + U32 scount; /* segment count */ + U32 size; /* segment size */ + U32 addr; /* segment physical address */ +} __attribute__ ((packed)) + singleB, *psingleB; +typedef struct { /* a single TCB */ + /* + ** +-----------------------+ + ** | 1 | one buffer in the TCB + ** +-----------------------+ + ** | <user's Context> | user's buffer reference + ** +-----------------------+ + ** | 1 | one segment buffer + ** +-----------------------+ _ + ** | <buffer size> | size \ + ** +-----------------------+ \ segment descriptor + ** | <physical address> | physical address of buffer / + ** +-----------------------+ _/ + */ + U32 bcount; /* buffer count */ + singleB b; /* buffer */ + +} __attribute__ ((packed)) + singleTCB, *psingleTCB; /* When adding new entries, please add all 5 related changes, since @@ -104,121 +100,119 @@ singleTCB, *psingleTCB; typedef struct RC_user_tag RCuser_struct; /* 1) User structure entry */ -struct RC_user_tag -{ - int cmd; - union - { - /* GETINFO structure */ - struct RCgetinfo_tag { - unsigned long int mem_start; - unsigned long int mem_end; - unsigned long int base_addr; - unsigned char irq; - unsigned char dma; - unsigned char port; - } RCgetinfo; /* <---- RCgetinfo */ - - /* GETSPEED structure */ - struct RCgetspeed_tag { - U32 LinkSpeedCode; - } RCgetspeed; /* <---- RCgetspeed */ - - /* SETSPEED structure */ - struct RCsetspeed_tag { - U16 LinkSpeedCode; - } RCsetspeed; /* <---- RCsetspeed */ - - /* GETPROM structure */ - struct RCgetprom_tag { - U32 PromMode; - } RCgetprom; /* <---- RCgetprom */ - - /* SETPROM structure */ - struct RCsetprom_tag { - U16 PromMode; - } RCsetprom; /* <---- RCsetprom */ - - /* GETBROADCAST structure */ - struct RCgetbroadcast_tag { - U32 BroadcastMode; - } RCgetbroadcast; /* <---- RCgetbroadcast */ - - /* SETBROADCAST structure */ - struct RCsetbroadcast_tag { - U16 BroadcastMode; - } RCsetbroadcast; /* <---- RCsetbroadcast */ - - /* GETFIRMWAREVER structure */ - #define FirmStringLen 80 - struct RCgetfwver_tag { - U8 FirmString[FirmStringLen]; - } RCgetfwver; /* <---- RCgetfwver */ - - /* GETIPANDMASK structure */ - struct RCgetipnmask_tag { - U32 IpAddr; - U32 NetMask; - } RCgetipandmask; /* <---- RCgetipandmask */ - - /* SETIPANDMASK structure */ - struct RCsetipnmask_tag { - U32 IpAddr; - U32 NetMask; - } RCsetipandmask; /* <---- RCsetipandmask */ - - /* GETMAC structure */ - #define MAC_SIZE 10 - struct RCgetmac_tag { - U8 mac[MAC_SIZE]; - } RCgetmac; /* <---- RCgetmac */ - - /* SETMAC structure */ - struct RCsetmac_tag { - U8 mac[MAC_SIZE]; - } RCsetmac; /* <---- RCsetmac */ - - /* GETLINKSTATUS structure */ - struct RCgetlnkstatus_tag { - U32 ReturnStatus; - } RCgetlnkstatus; /* <---- RCgetlnkstatus */ - - /* GETLINKSTATISTICS structure */ - struct RCgetlinkstats_tag { - RCLINKSTATS StatsReturn; - } RCgetlinkstats; /* <---- RCgetlinkstats */ - - /* DEFAULT structure (when no command was recognized) */ - struct RCdefault_tag { - int rc; - } RCdefault; /* <---- RCdefault */ - - } data; - -}; /* struct RC_user_tag { ... } */ +struct RC_user_tag { + int cmd; + union { + /* GETINFO structure */ + struct RCgetinfo_tag { + unsigned long int mem_start; + unsigned long int mem_end; + unsigned long int base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; + } RCgetinfo; /* <---- RCgetinfo */ + + /* GETSPEED structure */ + struct RCgetspeed_tag { + U32 LinkSpeedCode; + } RCgetspeed; /* <---- RCgetspeed */ + + /* SETSPEED structure */ + struct RCsetspeed_tag { + U16 LinkSpeedCode; + } RCsetspeed; /* <---- RCsetspeed */ + + /* GETPROM structure */ + struct RCgetprom_tag { + U32 PromMode; + } RCgetprom; /* <---- RCgetprom */ + + /* SETPROM structure */ + struct RCsetprom_tag { + U16 PromMode; + } RCsetprom; /* <---- RCsetprom */ + + /* GETBROADCAST structure */ + struct RCgetbroadcast_tag { + U32 BroadcastMode; + } RCgetbroadcast; /* <---- RCgetbroadcast */ + + /* SETBROADCAST structure */ + struct RCsetbroadcast_tag { + U16 BroadcastMode; + } RCsetbroadcast; /* <---- RCsetbroadcast */ + + /* GETFIRMWAREVER structure */ +#define FirmStringLen 80 + struct RCgetfwver_tag { + U8 FirmString[FirmStringLen]; + } RCgetfwver; /* <---- RCgetfwver */ + + /* GETIPANDMASK structure */ + struct RCgetipnmask_tag { + U32 IpAddr; + U32 NetMask; + } RCgetipandmask; /* <---- RCgetipandmask */ + + /* SETIPANDMASK structure */ + struct RCsetipnmask_tag { + U32 IpAddr; + U32 NetMask; + } RCsetipandmask; /* <---- RCsetipandmask */ + + /* GETMAC structure */ +#define MAC_SIZE 10 + struct RCgetmac_tag { + U8 mac[MAC_SIZE]; + } RCgetmac; /* <---- RCgetmac */ + + /* SETMAC structure */ + struct RCsetmac_tag { + U8 mac[MAC_SIZE]; + } RCsetmac; /* <---- RCsetmac */ + + /* GETLINKSTATUS structure */ + struct RCgetlnkstatus_tag { + U32 ReturnStatus; + } RCgetlnkstatus; /* <---- RCgetlnkstatus */ + + /* GETLINKSTATISTICS structure */ + struct RCgetlinkstats_tag { + RCLINKSTATS StatsReturn; + } RCgetlinkstats; /* <---- RCgetlinkstats */ + + /* DEFAULT structure (when no command was recognized) */ + struct RCdefault_tag { + int rc; + } RCdefault; /* <---- RCdefault */ + + } data; + +}; /* struct RC_user_tag { ... } */ /* 2) User data entry */ /* RCUD = RedCreek User Data */ -union RC_user_data_tag { /* structure tags used are taken from RC_user_tag structure above */ - struct RCgetinfo_tag *getinfo; - struct RCgetspeed_tag *getspeed; - struct RCgetprom_tag *getprom; - struct RCgetbroadcast_tag *getbroadcast; - struct RCgetfwver_tag *getfwver; - struct RCgetipnmask_tag *getipandmask; - struct RCgetmac_tag *getmac; - struct RCgetlnkstatus_tag *getlinkstatus; - struct RCgetlinkstats_tag *getlinkstatistics; - struct RCdefault_tag *rcdefault; - struct RCsetspeed_tag *setspeed; - struct RCsetprom_tag *setprom; - struct RCsetbroadcast_tag *setbroadcast; - struct RCsetipnmask_tag *setipandmask; - struct RCsetmac_tag *setmac; -} _RC_user_data; /* declare as a global, so the defines below will work */ +union RC_user_data_tag { /* structure tags used are taken from RC_user_tag structure above */ + struct RCgetinfo_tag *getinfo; + struct RCgetspeed_tag *getspeed; + struct RCgetprom_tag *getprom; + struct RCgetbroadcast_tag *getbroadcast; + struct RCgetfwver_tag *getfwver; + struct RCgetipnmask_tag *getipandmask; + struct RCgetmac_tag *getmac; + struct RCgetlnkstatus_tag *getlinkstatus; + struct RCgetlinkstats_tag *getlinkstatistics; + struct RCdefault_tag *rcdefault; + struct RCsetspeed_tag *setspeed; + struct RCsetprom_tag *setprom; + struct RCsetbroadcast_tag *setbroadcast; + struct RCsetipnmask_tag *setipandmask; + struct RCsetmac_tag *setmac; +} _RC_user_data; /* declare as a global, so the defines below will work */ /* 3) Structure short-cut entry */ -/* define structure short-cuts */ /* structure names are taken from RC_user_tag structure above */ +/* define structure short-cuts *//* structure names are taken from RC_user_tag structure above */ #define RCUS_GETINFO data.RCgetinfo; #define RCUS_GETSPEED data.RCgetspeed; #define RCUS_GETPROM data.RCgetprom; @@ -236,7 +230,7 @@ union RC_user_data_tag { /* structure tags used are taken from RC_user_ta #define RCUS_SETMAC data.RCsetmac; /* 4) Data short-cut entry */ -/* define data short-cuts */ /* pointer names are from RC_user_data_tag union (just below RC_user_tag) */ +/* define data short-cuts *//* pointer names are from RC_user_data_tag union (just below RC_user_tag) */ #define RCUD_GETINFO _RC_user_data.getinfo #define RCUD_GETSPEED _RC_user_data.getspeed #define RCUD_GETPROM _RC_user_data.getprom @@ -295,5 +289,4 @@ union RC_user_data_tag { /* structure tags used are taken from RC_user_ta RCUD_GETINFO->base_addr, RCUD_GETINFO->irq); */ -#endif /* RCIF_H */ - +#endif /* RCIF_H */ diff --git a/drivers/net/rclanmtl.c b/drivers/net/rclanmtl.c index c3393aa65e2d..834d670df2c0 100644 --- a/drivers/net/rclanmtl.c +++ b/drivers/net/rclanmtl.c @@ -42,10 +42,9 @@ #include "rclanmtl.h" /* RedCreek LAN device Target ID */ -#define RC_LAN_TARGET_ID 0x10 +#define RC_LAN_TARGET_ID 0x10 /* RedCreek's OSM default LAN receive Initiator */ -#define DEFAULT_RECV_INIT_CONTEXT 0xA17 - +#define DEFAULT_RECV_INIT_CONTEXT 0xA17 /* ** I2O message structures @@ -102,17 +101,14 @@ #define I2O_EXEC_SYS_QUIESCE 0xC3 #define I2O_EXEC_SYS_TAB_SET 0xA3 - /* Init Outbound Q status */ #define I2O_EXEC_OUTBOUND_INIT_IN_PROGRESS 0x01 #define I2O_EXEC_OUTBOUND_INIT_REJECTED 0x02 #define I2O_EXEC_OUTBOUND_INIT_FAILED 0x03 #define I2O_EXEC_OUTBOUND_INIT_COMPLETE 0x04 - #define I2O_UTIL_NOP 0x00 - /* I2O Get Status State values */ #define I2O_IOP_STATE_INITIALIZING 0x01 @@ -123,7 +119,6 @@ #define I2O_IOP_STATE_FAILED 0x10 #define I2O_IOP_STATE_FAULTED 0x11 - /* Defines for Request Status Codes: Table 3-1 Reply Status Codes. */ #define I2O_REPLY_STATUS_SUCCESS 0x00 @@ -139,7 +134,6 @@ #define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0A #define I2O_REPLY_STATUS_PROGRESS_REPORT 0x80 - /* DetailedStatusCode defines for ALL messages: Table 3-2 Detailed Status Codes.*/ #define I2O_DETAIL_STATUS_SUCCESS 0x0000 @@ -203,17 +197,17 @@ #define I2O_HOST_TID 0xB91 /* RedCreek I2O private message codes */ -#define RC_PRIVATE_GET_MAC_ADDR 0x0001/**/ /* OBSOLETE */ +#define RC_PRIVATE_GET_MAC_ADDR 0x0001/**/ /* OBSOLETE */ #define RC_PRIVATE_SET_MAC_ADDR 0x0002 #define RC_PRIVATE_GET_NIC_STATS 0x0003 #define RC_PRIVATE_GET_LINK_STATUS 0x0004 #define RC_PRIVATE_SET_LINK_SPEED 0x0005 #define RC_PRIVATE_SET_IP_AND_MASK 0x0006 -/* #define RC_PRIVATE_GET_IP_AND_MASK 0x0007 */ /* OBSOLETE */ +/* #define RC_PRIVATE_GET_IP_AND_MASK 0x0007 *//* OBSOLETE */ #define RC_PRIVATE_GET_LINK_SPEED 0x0008 #define RC_PRIVATE_GET_FIRMWARE_REV 0x0009 /* #define RC_PRIVATE_GET_MAC_ADDR 0x000A */ -#define RC_PRIVATE_GET_IP_AND_MASK 0x000B +#define RC_PRIVATE_GET_IP_AND_MASK 0x000B #define RC_PRIVATE_DEBUG_MSG 0x000C #define RC_PRIVATE_REPORT_DRIVER_CAPABILITY 0x000D #define RC_PRIVATE_SET_PROMISCUOUS_MODE 0x000e @@ -223,30 +217,26 @@ #define RC_PRIVATE_REBOOT 0x00FF - /* I2O message header */ -typedef struct _I2O_MESSAGE_FRAME -{ - U8 VersionOffset; - U8 MsgFlags; - U16 MessageSize; - BF TargetAddress:I2O_TID_SZ; - BF InitiatorAddress:I2O_TID_SZ; - BF Function:I2O_FUNCTION_SZ; - U32 InitiatorContext; - /* SGL[] */ -} -I2O_MESSAGE_FRAME, *PI2O_MESSAGE_FRAME; - +typedef struct _I2O_MESSAGE_FRAME { + U8 VersionOffset; + U8 MsgFlags; + U16 MessageSize; + BF TargetAddress:I2O_TID_SZ; + BF InitiatorAddress:I2O_TID_SZ; + BF Function:I2O_FUNCTION_SZ; + U32 InitiatorContext; + /* SGL[] */ +} I2O_MESSAGE_FRAME, *PI2O_MESSAGE_FRAME; /* assumed a 16K minus 256 byte space for outbound queue message frames */ #define MSG_FRAME_SIZE 512 #define NMBR_MSG_FRAMES 30 /* - ** in reserved space right after PAB in host memory is area for returning - ** values from card - */ + ** in reserved space right after PAB in host memory is area for returning + ** values from card + */ /* ** typedef NICSTAT @@ -254,43 +244,37 @@ I2O_MESSAGE_FRAME, *PI2O_MESSAGE_FRAME; ** Data structure for NIC statistics retruned from PCI card. Data copied from ** here to user allocated RCLINKSTATS (see rclanmtl.h) structure. */ -typedef struct tag_NicStat -{ - unsigned long TX_good; - unsigned long TX_maxcol; - unsigned long TX_latecol; - unsigned long TX_urun; - unsigned long TX_crs; /* lost carrier sense */ - unsigned long TX_def; /* transmit deferred */ - unsigned long TX_singlecol; /* single collisions */ - unsigned long TX_multcol; - unsigned long TX_totcol; - unsigned long Rcv_good; - unsigned long Rcv_CRCerr; - unsigned long Rcv_alignerr; - unsigned long Rcv_reserr; /* rnr'd pkts */ - unsigned long Rcv_orun; - unsigned long Rcv_cdt; - unsigned long Rcv_runt; - unsigned long dump_status; /* last field directly from the chip */ -} -NICSTAT, *P_NICSTAT; - - -#define DUMP_DONE 0x0000A005 /* completed statistical dump */ -#define DUMP_CLEAR 0x0000A007 /* completed stat dump and clear counters */ - +typedef struct tag_NicStat { + unsigned long TX_good; + unsigned long TX_maxcol; + unsigned long TX_latecol; + unsigned long TX_urun; + unsigned long TX_crs; /* lost carrier sense */ + unsigned long TX_def; /* transmit deferred */ + unsigned long TX_singlecol; /* single collisions */ + unsigned long TX_multcol; + unsigned long TX_totcol; + unsigned long Rcv_good; + unsigned long Rcv_CRCerr; + unsigned long Rcv_alignerr; + unsigned long Rcv_reserr; /* rnr'd pkts */ + unsigned long Rcv_orun; + unsigned long Rcv_cdt; + unsigned long Rcv_runt; + unsigned long dump_status; /* last field directly from the chip */ +} NICSTAT, *P_NICSTAT; + +#define DUMP_DONE 0x0000A005 /* completed statistical dump */ +#define DUMP_CLEAR 0x0000A007 /* completed stat dump and clear counters */ static volatile int msgFlag; - /* local function prototypes */ -static void ProcessOutboundI2OMsg(PPAB pPab, U32 phyMsgAddr); -static int FillI2OMsgSGLFromTCB(PU32 pMsg, PRCTCB pXmitCntrlBlock); -static int GetI2OStatus(PPAB pPab); -static int SendI2OOutboundQInitMsg(PPAB pPab); -static int SendEnableSysMsg(PPAB pPab); - +static void ProcessOutboundI2OMsg (PPAB pPab, U32 phyMsgAddr); +static int FillI2OMsgSGLFromTCB (PU32 pMsg, PRCTCB pXmitCntrlBlock); +static int GetI2OStatus (PPAB pPab); +static int SendI2OOutboundQInitMsg (PPAB pPab); +static int SendEnableSysMsg (PPAB pPab); /* ** ========================================================================= @@ -308,85 +292,89 @@ static int SendEnableSysMsg(PPAB pPab); ** ========================================================================= */ RC_RETURN -RCInitI2OMsgLayer(struct net_device *dev, - PFNTXCALLBACK TransmitCallbackFunction, - PFNRXCALLBACK ReceiveCallbackFunction, - PFNCALLBACK RebootCallbackFunction) +RCInitI2OMsgLayer (struct net_device *dev, + PFNTXCALLBACK TransmitCallbackFunction, + PFNRXCALLBACK ReceiveCallbackFunction, + PFNCALLBACK RebootCallbackFunction) { - int result; - PPAB pPab; - U32 pciBaseAddr = dev->base_addr; - PDPA pDpa = dev->priv; - PU8 p_msgbuf = pDpa->PLanApiPA; - PU8 p_phymsgbuf = (PU8)virt_to_bus((void *) p_msgbuf); - - dprintk("InitI2O: Adapter:0x%04ux ATU:0x%08ulx msgbuf:0x%08ulx phymsgbuf:0x%08ulx\n" - "TransmitCallbackFunction:0x%08ulx ReceiveCallbackFunction:0x%08ulx\n", - pDpa->id, pciBaseAddr, (u32)p_msgbuf, (u32)p_phymsgbuf, - (u32)TransmitCallbackFunction, (u32)ReceiveCallbackFunction); - - - /* Check if this interface already initialized - if so, shut it down */ - if (pDpa->pPab != NULL) { - printk(KERN_WARNING "(rcpci45 driver:) pDpa->pPab [%d] != NULL\n", pDpa->id); + int result; + PPAB pPab; + U32 pciBaseAddr = dev->base_addr; + PDPA pDpa = dev->priv; + PU8 p_msgbuf = pDpa->PLanApiPA; + PU8 p_phymsgbuf = (PU8) virt_to_bus ((void *) p_msgbuf); + + dprintk + ("InitI2O: Adapter:0x%04ux ATU:0x%08ulx msgbuf:0x%08ulx phymsgbuf:0x%08ulx\n" + "TransmitCallbackFunction:0x%08ulx ReceiveCallbackFunction:0x%08ulx\n", + pDpa->id, pciBaseAddr, (u32) p_msgbuf, (u32) p_phymsgbuf, + (u32) TransmitCallbackFunction, (u32) ReceiveCallbackFunction); + + /* Check if this interface already initialized - if so, shut it down */ + if (pDpa->pPab != NULL) { + printk (KERN_WARNING + "(rcpci45 driver:) pDpa->pPab [%d] != NULL\n", + pDpa->id); /* RCResetLANCard(pDpa->id, 0, (PU32)NULL, (PFNCALLBACK)NULL); */ - pDpa->pPab = NULL; - } - - /* store adapter instance values in adapter block. - * Adapter block is at beginning of message buffer */ - - pPab = kmalloc(sizeof(*pPab), GFP_KERNEL); - if (!pPab) { - printk(KERN_ERR "(rcpci45 driver:) RCInitI2OMsgLayer: Could not allocate memory for PAB struct!\n"); - result = RC_RTN_MALLOC_ERROR; - goto err_out; - } - - memset(pPab, 0, sizeof(*pPab)); - pDpa->pPab = pPab; - pPab->p_atu = (PATU)pciBaseAddr; - pPab->pPci45LinBaseAddr = (PU8)pciBaseAddr; - - /* Set outbound message frame addr */ - pPab->outMsgBlockPhyAddr = (U32)p_phymsgbuf; - pPab->pLinOutMsgBlock = (PU8)p_msgbuf; - - /* store callback function addresses */ - pPab->pTransCallbackFunc = TransmitCallbackFunction; - pPab->pRecvCallbackFunc = ReceiveCallbackFunction; - pPab->pRebootCallbackFunc = RebootCallbackFunction; - pPab->pCallbackFunc = (PFNCALLBACK)NULL; - - /* - ** Initialize I2O IOP - */ - result = GetI2OStatus(pPab); - - if (result != RC_RTN_NO_ERROR) - goto err_out_dealloc; - - if (pPab->IOPState == I2O_IOP_STATE_OPERATIONAL) { - printk(KERN_INFO "(rcpci45 driver:) pPab->IOPState == op: resetting adapter\n"); - RCResetLANCard(dev, 0, (PU32)NULL, (PFNCALLBACK)NULL); - } - - result = SendI2OOutboundQInitMsg(pPab); - - if (result != RC_RTN_NO_ERROR) - goto err_out_dealloc; - - result = SendEnableSysMsg(pPab); - - if (result != RC_RTN_NO_ERROR) - goto err_out_dealloc; - - return RC_RTN_NO_ERROR; - - err_out_dealloc: - kfree(pPab); - err_out: - return result; + pDpa->pPab = NULL; + } + + /* store adapter instance values in adapter block. + * Adapter block is at beginning of message buffer */ + + pPab = kmalloc (sizeof (*pPab), GFP_KERNEL); + if (!pPab) { + printk (KERN_ERR + "(rcpci45 driver:) RCInitI2OMsgLayer: Could not allocate memory for PAB struct!\n"); + result = RC_RTN_MALLOC_ERROR; + goto err_out; + } + + memset (pPab, 0, sizeof (*pPab)); + pDpa->pPab = pPab; + pPab->p_atu = (PATU) pciBaseAddr; + pPab->pPci45LinBaseAddr = (PU8) pciBaseAddr; + + /* Set outbound message frame addr */ + pPab->outMsgBlockPhyAddr = (U32) p_phymsgbuf; + pPab->pLinOutMsgBlock = (PU8) p_msgbuf; + + /* store callback function addresses */ + pPab->pTransCallbackFunc = TransmitCallbackFunction; + pPab->pRecvCallbackFunc = ReceiveCallbackFunction; + pPab->pRebootCallbackFunc = RebootCallbackFunction; + pPab->pCallbackFunc = (PFNCALLBACK) NULL; + + /* + ** Initialize I2O IOP + */ + result = GetI2OStatus (pPab); + + if (result != RC_RTN_NO_ERROR) + goto err_out_dealloc; + + if (pPab->IOPState == I2O_IOP_STATE_OPERATIONAL) { + printk (KERN_INFO + "(rcpci45 driver:) pPab->IOPState == op: resetting adapter\n"); + RCResetLANCard (dev, 0, (PU32) NULL, (PFNCALLBACK) NULL); + } + + result = SendI2OOutboundQInitMsg (pPab); + + if (result != RC_RTN_NO_ERROR) + goto err_out_dealloc; + + result = SendEnableSysMsg (pPab); + + if (result != RC_RTN_NO_ERROR) + goto err_out_dealloc; + + return RC_RTN_NO_ERROR; + + err_out_dealloc: + kfree (pPab); + err_out: + return result; } /* @@ -399,35 +387,34 @@ RCInitI2OMsgLayer(struct net_device *dev, ** queue is not emtpy. ** ========================================================================= */ -#define i960_OUT_POST_Q_INT_BIT 0x0008 /* bit set masks interrupts */ +#define i960_OUT_POST_Q_INT_BIT 0x0008 /* bit set masks interrupts */ -RC_RETURN RCDisableI2OInterrupts(struct net_device *dev) +RC_RETURN +RCDisableI2OInterrupts (struct net_device * dev) { - PPAB pPab = ((PDPA)dev->priv)->pPab; + PPAB pPab = ((PDPA) dev->priv)->pPab; + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - pPab->p_atu->OutIntMask |= i960_OUT_POST_Q_INT_BIT; + pPab->p_atu->OutIntMask |= i960_OUT_POST_Q_INT_BIT; - return RC_RTN_NO_ERROR; + return RC_RTN_NO_ERROR; } -RC_RETURN RCEnableI2OInterrupts(struct net_device *dev) +RC_RETURN +RCEnableI2OInterrupts (struct net_device * dev) { - PPAB pPab = ((PDPA)dev->priv)->pPab; + PPAB pPab = ((PDPA) dev->priv)->pPab; + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - pPab->p_atu->OutIntMask &= ~i960_OUT_POST_Q_INT_BIT; - - return RC_RTN_NO_ERROR; + pPab->p_atu->OutIntMask &= ~i960_OUT_POST_Q_INT_BIT; -} + return RC_RTN_NO_ERROR; +} /* ** ========================================================================= @@ -435,55 +422,53 @@ RC_RETURN RCEnableI2OInterrupts(struct net_device *dev) ** ========================================================================= */ RC_RETURN -RCI2OSendPacket(struct net_device *dev, U32 InitiatorContext, - PRCTCB pTransCtrlBlock) +RCI2OSendPacket (struct net_device * dev, U32 InitiatorContext, + PRCTCB pTransCtrlBlock) { - U32 msgOffset; - PU32 pMsg; - int size; - PPAB pPab = ((PDPA)dev->priv)->pPab; - - - dprintk("RCI2OSendPacket()...\n"); - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - /* get Inbound free Q entry - reading from In Q gets free Q entry */ - /* offset to Msg Frame in PCI msg block */ - - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) - { - dprintk("RCI2OSendPacket(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virual address of msg - virual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); - - size = FillI2OMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock); - - if (size == -1) /* error processing TCB - send NOP msg */ - { - dprintk("RCI2OSendPacket(): Error Rrocess TCB!\n"); - pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_UTIL_NOP << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - return RC_RTN_TCB_ERROR; - } - else /* send over msg header */ - { - pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */ - pMsg[1] = I2O_LAN_PACKET_SEND << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = InitiatorContext; - pMsg[3] = 0; /* batch reply */ - /* post to Inbound Post Q */ - pPab->p_atu->InQueue = msgOffset; - return RC_RTN_NO_ERROR; - } + U32 msgOffset; + PU32 pMsg; + int size; + PPAB pPab = ((PDPA) dev->priv)->pPab; + + dprintk ("RCI2OSendPacket()...\n"); + + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; + + /* get Inbound free Q entry - reading from In Q gets free Q entry */ + /* offset to Msg Frame in PCI msg block */ + + msgOffset = pPab->p_atu->InQueue; + + if (msgOffset == 0xFFFFFFFF) { + dprintk ("RCI2OSendPacket(): Inbound Free Q empty!\n"); + return RC_RTN_FREE_Q_EMPTY; + } + + /* calc virual address of msg - virual already mapped to physical */ + pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); + + size = FillI2OMsgSGLFromTCB (pMsg + 4, pTransCtrlBlock); + + if (size == -1) { /* error processing TCB - send NOP msg */ + dprintk ("RCI2OSendPacket(): Error Rrocess TCB!\n"); + pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = + I2O_UTIL_NOP << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + return RC_RTN_TCB_ERROR; + } else { /* send over msg header */ + + pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */ + pMsg[1] = + I2O_LAN_PACKET_SEND << 24 | I2O_HOST_TID << 12 | + RC_LAN_TARGET_ID; + pMsg[2] = InitiatorContext; + pMsg[3] = 0; /* batch reply */ + /* post to Inbound Post Q */ + pPab->p_atu->InQueue = msgOffset; + return RC_RTN_NO_ERROR; + } } - /* ** ========================================================================= @@ -495,56 +480,57 @@ RCI2OSendPacket(struct net_device *dev, U32 InitiatorContext, ** ========================================================================= */ RC_RETURN -RCPostRecvBuffers(struct net_device *dev, PRCTCB pTransCtrlBlock) +RCPostRecvBuffers (struct net_device * dev, PRCTCB pTransCtrlBlock) { - U32 msgOffset; - PU32 pMsg; - int size; - PPAB pPab = ((PDPA)dev->priv)->pPab; - - dprintk("RCPostRecvBuffers()...\n"); - - /* search for DeviceHandle */ - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - /* get Inbound free Q entry - reading from In Q gets free Q entry */ - /* offset to Msg Frame in PCI msg block */ - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) - { - dprintk("RCPostRecvBuffers(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - /* calc virual address of msg - virual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); - - size = FillI2OMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock); - - if (size == -1) /* error prcessing TCB - send 3 DWORD private msg == NOP */ - { - dprintk("RCPostRecvBuffers(): Error Processing TCB! size = %d\n", size); - pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_UTIL_NOP << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - /* post to Post Q */ - pPab->p_atu->InQueue = msgOffset; - return RC_RTN_TCB_ERROR; - } - else /* send over size msg header */ - { - pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */ - pMsg[1] = I2O_LAN_RECEIVE_POST << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = *(PU32)pTransCtrlBlock; /* number of packet buffers */ - /* post to Post Q */ - pPab->p_atu->InQueue = msgOffset; - return RC_RTN_NO_ERROR; - } + U32 msgOffset; + PU32 pMsg; + int size; + PPAB pPab = ((PDPA) dev->priv)->pPab; + + dprintk ("RCPostRecvBuffers()...\n"); + + /* search for DeviceHandle */ + + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; + + /* get Inbound free Q entry - reading from In Q gets free Q entry */ + /* offset to Msg Frame in PCI msg block */ + msgOffset = pPab->p_atu->InQueue; + + if (msgOffset == 0xFFFFFFFF) { + dprintk ("RCPostRecvBuffers(): Inbound Free Q empty!\n"); + return RC_RTN_FREE_Q_EMPTY; + } + /* calc virual address of msg - virual already mapped to physical */ + pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); + + size = FillI2OMsgSGLFromTCB (pMsg + 4, pTransCtrlBlock); + + if (size == -1) { /* error prcessing TCB - send 3 DWORD private msg == NOP */ + dprintk + ("RCPostRecvBuffers(): Error Processing TCB! size = %d\n", + size); + pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = + I2O_UTIL_NOP << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + /* post to Post Q */ + pPab->p_atu->InQueue = msgOffset; + return RC_RTN_TCB_ERROR; + } else { /* send over size msg header */ + + pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */ + pMsg[1] = + I2O_LAN_RECEIVE_POST << 24 | I2O_HOST_TID << 12 | + RC_LAN_TARGET_ID; + pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; + pMsg[3] = *(PU32) pTransCtrlBlock; /* number of packet buffers */ + /* post to Post Q */ + pPab->p_atu->InQueue = msgOffset; + return RC_RTN_NO_ERROR; + } } - /* ** ========================================================================= ** RCProcI2OMsgQ() @@ -552,106 +538,112 @@ RCPostRecvBuffers(struct net_device *dev, PRCTCB pTransCtrlBlock) ** Process I2O outbound message queue until empty. ** ========================================================================= */ -void -RCProcI2OMsgQ(struct net_device *dev) +void +RCProcI2OMsgQ (struct net_device *dev) { - U32 phyAddrMsg; - PU8 p8Msg; - PU32 p32; - U16 count; - PPAB pPab = ((PDPA)dev->priv)->pPab; - unsigned char debug_msg[20]; - - - if (pPab == NULL) - return; - - phyAddrMsg = pPab->p_atu->OutQueue; - - while (phyAddrMsg != 0xFFFFFFFF) - { - p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr); - p32 = (PU32)p8Msg; - - dprintk("msg: 0x%x 0x%x \n", p8Msg[7], p32[5]); - - /* Send Packet Reply Msg */ - if (I2O_LAN_PACKET_SEND == p8Msg[7]) { /* function code byte */ - count = *(PU16)(p8Msg+2); - count -= p8Msg[0] >> 4; - /* status, count, context[], adapter */ - (*pPab->pTransCallbackFunc)(p8Msg[19], count, p32+5, dev); - } else if (I2O_LAN_RECEIVE_POST == p8Msg[7]) { /* Receive Packet Reply Msg */ - dprintk("I2O_RECV_REPLY pPab:0x%08ulx p8Msg:0x%08ulx p32:0x%08ulx\n", (u32)pPab, (u32)p8Msg, (u32)p32); - dprintk("msg: 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[0], p32[1], p32[2], p32[3]); - dprintk(" 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[4], p32[5], p32[6], p32[7]); - dprintk(" 0x%08ulx:0X%08ulx:0x%08ulx:0x%08ulx\n", - p32[8], p32[9], p32[10], p32[11]); - /* status, count, buckets remaining, packetParmBlock, adapter */ - (*pPab->pRecvCallbackFunc)(p8Msg[19], p8Msg[12], p32[5], p32+6, dev); - } else if (I2O_LAN_RESET == p8Msg[7] || I2O_LAN_SHUTDOWN == p8Msg[7]) - if (pPab->pCallbackFunc) - (*pPab->pCallbackFunc)(p8Msg[19],0,0,dev); - else - pPab->pCallbackFunc = (PFNCALLBACK) 1; - else if (I2O_PRIVATE == p8Msg[7]) { - dprintk("i2o private 0x%x, 0x%x \n", p8Msg[7], p32[5]); - switch (p32[5]) - { - case RC_PRIVATE_DEBUG_MSG: - msgFlag = 1; - dprintk("Received I2O_PRIVATE msg\n"); - debug_msg[15] = (p32[6]&0xff000000) >> 24; - debug_msg[14] = (p32[6]&0x00ff0000) >> 16; - debug_msg[13] = (p32[6]&0x0000ff00) >> 8; - debug_msg[12] = (p32[6]&0x000000ff); - - debug_msg[11] = (p32[7]&0xff000000) >> 24; - debug_msg[10] = (p32[7]&0x00ff0000) >> 16; - debug_msg[ 9] = (p32[7]&0x0000ff00) >> 8; - debug_msg[ 8] = (p32[7]&0x000000ff); - - debug_msg[ 7] = (p32[8]&0xff000000) >> 24; - debug_msg[ 6] = (p32[8]&0x00ff0000) >> 16; - debug_msg[ 5] = (p32[8]&0x0000ff00) >> 8; - debug_msg[ 4] = (p32[8]&0x000000ff); - - debug_msg[ 3] = (p32[9]&0xff000000) >> 24; - debug_msg[ 2] = (p32[9]&0x00ff0000) >> 16; - debug_msg[ 1] = (p32[9]&0x0000ff00) >> 8; - debug_msg[ 0] = (p32[9]&0x000000ff); - - debug_msg[16] = '\0'; - dprintk("%s", debug_msg); - break; - case RC_PRIVATE_REBOOT: - dprintk("Adapter reboot initiated...\n"); - if (pPab->pRebootCallbackFunc) - (*pPab->pRebootCallbackFunc)(0,0,0,dev); - break; - default: - printk(KERN_WARNING "(rcpci45 driver:) Unknown private I2O msg received: 0x%x\n", p32[5]); - break; - } - } - - /* - ** Process other Msg's - */ - else - ProcessOutboundI2OMsg(pPab, phyAddrMsg); - - /* return MFA to outbound free Q*/ - pPab->p_atu->OutQueue = phyAddrMsg; - - /* any more msgs? */ - phyAddrMsg = pPab->p_atu->OutQueue; - } + U32 phyAddrMsg; + PU8 p8Msg; + PU32 p32; + U16 count; + PPAB pPab = ((PDPA) dev->priv)->pPab; + unsigned char debug_msg[20]; + + if (pPab == NULL) + return; + + phyAddrMsg = pPab->p_atu->OutQueue; + + while (phyAddrMsg != 0xFFFFFFFF) { + p8Msg = + pPab->pLinOutMsgBlock + (phyAddrMsg - + pPab->outMsgBlockPhyAddr); + p32 = (PU32) p8Msg; + + dprintk ("msg: 0x%x 0x%x \n", p8Msg[7], p32[5]); + + /* Send Packet Reply Msg */ + if (I2O_LAN_PACKET_SEND == p8Msg[7]) { /* function code byte */ + count = *(PU16) (p8Msg + 2); + count -= p8Msg[0] >> 4; + /* status, count, context[], adapter */ + (*pPab->pTransCallbackFunc) (p8Msg[19], count, p32 + 5, + dev); + } else if (I2O_LAN_RECEIVE_POST == p8Msg[7]) { /* Receive Packet Reply Msg */ + dprintk + ("I2O_RECV_REPLY pPab:0x%08ulx p8Msg:0x%08ulx p32:0x%08ulx\n", + (u32) pPab, (u32) p8Msg, (u32) p32); + dprintk ("msg: 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + p32[0], p32[1], p32[2], p32[3]); + dprintk (" 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + p32[4], p32[5], p32[6], p32[7]); + dprintk (" 0x%08ulx:0X%08ulx:0x%08ulx:0x%08ulx\n", + p32[8], p32[9], p32[10], p32[11]); + /* status, count, buckets remaining, packetParmBlock, adapter */ + (*pPab->pRecvCallbackFunc) (p8Msg[19], p8Msg[12], + p32[5], p32 + 6, dev); + } else if (I2O_LAN_RESET == p8Msg[7] + || I2O_LAN_SHUTDOWN == p8Msg[7]) + if (pPab->pCallbackFunc) + (*pPab->pCallbackFunc) (p8Msg[19], 0, 0, dev); + else + pPab->pCallbackFunc = (PFNCALLBACK) 1; + else if (I2O_PRIVATE == p8Msg[7]) { + dprintk ("i2o private 0x%x, 0x%x \n", p8Msg[7], p32[5]); + switch (p32[5]) { + case RC_PRIVATE_DEBUG_MSG: + msgFlag = 1; + dprintk ("Received I2O_PRIVATE msg\n"); + debug_msg[15] = (p32[6] & 0xff000000) >> 24; + debug_msg[14] = (p32[6] & 0x00ff0000) >> 16; + debug_msg[13] = (p32[6] & 0x0000ff00) >> 8; + debug_msg[12] = (p32[6] & 0x000000ff); + + debug_msg[11] = (p32[7] & 0xff000000) >> 24; + debug_msg[10] = (p32[7] & 0x00ff0000) >> 16; + debug_msg[9] = (p32[7] & 0x0000ff00) >> 8; + debug_msg[8] = (p32[7] & 0x000000ff); + + debug_msg[7] = (p32[8] & 0xff000000) >> 24; + debug_msg[6] = (p32[8] & 0x00ff0000) >> 16; + debug_msg[5] = (p32[8] & 0x0000ff00) >> 8; + debug_msg[4] = (p32[8] & 0x000000ff); + + debug_msg[3] = (p32[9] & 0xff000000) >> 24; + debug_msg[2] = (p32[9] & 0x00ff0000) >> 16; + debug_msg[1] = (p32[9] & 0x0000ff00) >> 8; + debug_msg[0] = (p32[9] & 0x000000ff); + + debug_msg[16] = '\0'; + dprintk ("%s", debug_msg); + break; + case RC_PRIVATE_REBOOT: + dprintk ("Adapter reboot initiated...\n"); + if (pPab->pRebootCallbackFunc) + (*pPab->pRebootCallbackFunc) (0, 0, 0, + dev); + break; + default: + printk (KERN_WARNING + "(rcpci45 driver:) Unknown private I2O msg received: 0x%x\n", + p32[5]); + break; + } + } + + /* + ** Process other Msg's + */ + else + ProcessOutboundI2OMsg (pPab, phyAddrMsg); + + /* return MFA to outbound free Q */ + pPab->p_atu->OutQueue = phyAddrMsg; + + /* any more msgs? */ + phyAddrMsg = pPab->p_atu->OutQueue; + } } - /* ** ========================================================================= ** Returns LAN interface statistical counters to space provided by caller at @@ -661,79 +653,75 @@ RCProcI2OMsgQ(struct net_device *dev) ** ========================================================================= */ RC_RETURN -RCGetLinkStatistics(struct net_device *dev, - P_RCLINKSTATS StatsReturnAddr, - PFNWAITCALLBACK WaitCallback) +RCGetLinkStatistics (struct net_device *dev, + P_RCLINKSTATS StatsReturnAddr, + PFNWAITCALLBACK WaitCallback) { - U32 msgOffset; - volatile U32 timeout; - volatile PU32 pMsg; - volatile PU32 p32, pReturnAddr; - P_NICSTAT pStats; - int i; - PPAB pPab = ((PDPA)dev->priv)->pPab; - + U32 msgOffset; + volatile U32 timeout; + volatile PU32 pMsg; + volatile PU32 p32, pReturnAddr; + P_NICSTAT pStats; + int i; + PPAB pPab = ((PDPA) dev->priv)->pPab; /*dprintk("Get82558Stats() StatsReturnAddr:0x%08ulx\n", StatsReturnAddr); */ - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - msgOffset = pPab->p_atu->InQueue; + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; + + msgOffset = pPab->p_atu->InQueue; - if (msgOffset == 0xFFFFFFFF) - { - dprintk("Get8255XStats(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } + if (msgOffset == 0xFFFFFFFF) { + dprintk ("Get8255XStats(): Inbound Free Q empty!\n"); + return RC_RTN_FREE_Q_EMPTY; + } - /* calc virual address of msg - virual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + /* calc virual address of msg - virual already mapped to physical */ + pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); /*dprintk("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/ /*dprintk("Get82558Stats - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = 0x112; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_NIC_STATS; - pMsg[5] = pPab->outMsgBlockPhyAddr; - - p32 = (PU32) pPab->outMsgBlockPhyAddr; - pStats = (P_NICSTAT)pPab->pLinOutMsgBlock; - pStats->dump_status = 0xFFFFFFFF; - - /* post to Inbound Post Q */ - pPab->p_atu->InQueue = msgOffset; - - timeout = 100000; - while (1) - { - if (WaitCallback) - (*WaitCallback)(); - - udelay(10); - - if (pStats->dump_status != 0xFFFFFFFF) - break; - - if (!timeout--) - { - dprintk("RCGet82558Stats() Timeout waiting for NIC statistics\n"); - return RC_RTN_MSG_REPLY_TIMEOUT; - } - } - - pReturnAddr = (PU32)StatsReturnAddr; - - /* copy Nic stats to user's structure */ - for (i = 0; i < (int) sizeof(RCLINKSTATS) / 4; i++) - pReturnAddr[i] = p32[i]; - - return RC_RTN_NO_ERROR; -} + pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; + pMsg[3] = 0x112; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_NIC_STATS; + pMsg[5] = pPab->outMsgBlockPhyAddr; + + p32 = (PU32) pPab->outMsgBlockPhyAddr; + pStats = (P_NICSTAT) pPab->pLinOutMsgBlock; + pStats->dump_status = 0xFFFFFFFF; + /* post to Inbound Post Q */ + pPab->p_atu->InQueue = msgOffset; + + timeout = 100000; + while (1) { + if (WaitCallback) + (*WaitCallback) (); + + udelay (10); + + if (pStats->dump_status != 0xFFFFFFFF) + break; + + if (!timeout--) { + dprintk + ("RCGet82558Stats() Timeout waiting for NIC statistics\n"); + return RC_RTN_MSG_REPLY_TIMEOUT; + } + } + + pReturnAddr = (PU32) StatsReturnAddr; + + /* copy Nic stats to user's structure */ + for (i = 0; i < (int) sizeof (RCLINKSTATS) / 4; i++) + pReturnAddr[i] = p32[i]; + + return RC_RTN_NO_ERROR; +} /* ** ========================================================================= @@ -741,67 +729,66 @@ RCGetLinkStatistics(struct net_device *dev, ** ========================================================================= */ RC_RETURN -RCGetLinkStatus(struct net_device *dev, PU32 ReturnAddr, - PFNWAITCALLBACK WaitCallback) +RCGetLinkStatus (struct net_device * dev, PU32 ReturnAddr, + PFNWAITCALLBACK WaitCallback) { - U32 msgOffset; - volatile U32 timeout; - volatile PU32 pMsg; - volatile PU32 p32; - PPAB pPab = ((PDPA)dev->priv)->pPab; + U32 msgOffset; + volatile U32 timeout; + volatile PU32 pMsg; + volatile PU32 p32; + PPAB pPab = ((PDPA) dev->priv)->pPab; + dprintk ("Get82558LinkStatus() ReturnPhysAddr:0x%08ulx\n", + (u32) ReturnAddr); - dprintk("Get82558LinkStatus() ReturnPhysAddr:0x%08ulx\n", (u32)ReturnAddr); + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - msgOffset = pPab->p_atu->InQueue; + msgOffset = pPab->p_atu->InQueue; - if (msgOffset == 0xFFFFFFFF) - { - dprintk("Get82558LinkStatus(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } + if (msgOffset == 0xFFFFFFFF) { + dprintk ("Get82558LinkStatus(): Inbound Free Q empty!\n"); + return RC_RTN_FREE_Q_EMPTY; + } - /* calc virual address of msg - virual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + /* calc virual address of msg - virual already mapped to physical */ + pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); /*dprintk("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/ /*dprintk("Get82558LinkStatus - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = 0x112; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_STATUS; - pMsg[5] = pPab->outMsgBlockPhyAddr; - - p32 = (PU32)pPab->pLinOutMsgBlock; - *p32 = 0xFFFFFFFF; - - /* post to Inbound Post Q */ - pPab->p_atu->InQueue = msgOffset; - - timeout = 100000; - while (1) { - if (WaitCallback) - (*WaitCallback)(); - - udelay(10); - - if (*p32 != 0xFFFFFFFF) - break; - - if (!timeout--) { - dprintk("Timeout waiting for link status\n"); - return RC_RTN_MSG_REPLY_TIMEOUT; - } - } - - *ReturnAddr = *p32; /* 1 = up 0 = down */ - - return RC_RTN_NO_ERROR; - + pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; + pMsg[3] = 0x112; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_STATUS; + pMsg[5] = pPab->outMsgBlockPhyAddr; + + p32 = (PU32) pPab->pLinOutMsgBlock; + *p32 = 0xFFFFFFFF; + + /* post to Inbound Post Q */ + pPab->p_atu->InQueue = msgOffset; + + timeout = 100000; + while (1) { + if (WaitCallback) + (*WaitCallback) (); + + udelay (10); + + if (*p32 != 0xFFFFFFFF) + break; + + if (!timeout--) { + dprintk ("Timeout waiting for link status\n"); + return RC_RTN_MSG_REPLY_TIMEOUT; + } + } + + *ReturnAddr = *p32; /* 1 = up 0 = down */ + + return RC_RTN_NO_ERROR; + } /* @@ -813,73 +800,68 @@ RCGetLinkStatus(struct net_device *dev, PU32 ReturnAddr, ** ========================================================================= */ RC_RETURN -RCGetMAC(struct net_device *dev, PFNWAITCALLBACK WaitCallback) +RCGetMAC (struct net_device * dev, PFNWAITCALLBACK WaitCallback) { - unsigned timeout; - U32 off; - PU8 mac = dev->dev_addr; - PU32 p; - U32 temp[2]; - PPAB pPab = ((PDPA)dev->priv)->pPab; - PATU p_atu; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - p_atu = pPab->p_atu; - - p_atu->EtherMacLow = 0; /* first zero return data */ - p_atu->EtherMacHi = 0; - - off = p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - p = (PU32)(pPab->pPci45LinBaseAddr + off); - - dprintk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", - (uint)p_atu, (uint)off, (uint)p); - /* setup private message */ - p[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; - p[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - p[2] = 0; /* initiator context */ - p[3] = 0x218; /* transaction context */ - p[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_MAC_ADDR; - - - p_atu->InQueue = off; /* send it to the I2O device */ - dprintk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", - (uint)p_atu, (uint)off, (uint)p); - - /* wait for the rcpci45 board to update the info */ - timeout = 1000000; - while (0 == p_atu->EtherMacLow) - { - if (WaitCallback) - (*WaitCallback)(); - - udelay(10); - - if (!timeout--) - { - printk("rc_getmac: Timeout\n"); - return RC_RTN_MSG_REPLY_TIMEOUT; - } - } - - /* read the mac address */ - temp[0] = p_atu->EtherMacLow; - temp[1] = p_atu->EtherMacHi; - memcpy((char *)mac, (char *)temp, 6); - - - dprintk("rc_getmac: 0x%x\n", (u32)mac); - - return RC_RTN_NO_ERROR; + unsigned timeout; + U32 off; + PU8 mac = dev->dev_addr; + PU32 p; + U32 temp[2]; + PPAB pPab = ((PDPA) dev->priv)->pPab; + PATU p_atu; + + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; + + p_atu = pPab->p_atu; + + p_atu->EtherMacLow = 0; /* first zero return data */ + p_atu->EtherMacHi = 0; + + off = p_atu->InQueue; /* get addresss of message */ + + if (0xFFFFFFFF == off) + return RC_RTN_FREE_Q_EMPTY; + + p = (PU32) (pPab->pPci45LinBaseAddr + off); + + dprintk ("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", + (uint) p_atu, (uint) off, (uint) p); + /* setup private message */ + p[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; + p[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + p[2] = 0; /* initiator context */ + p[3] = 0x218; /* transaction context */ + p[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_MAC_ADDR; + + p_atu->InQueue = off; /* send it to the I2O device */ + dprintk ("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", + (uint) p_atu, (uint) off, (uint) p); + + /* wait for the rcpci45 board to update the info */ + timeout = 1000000; + while (0 == p_atu->EtherMacLow) { + if (WaitCallback) + (*WaitCallback) (); + + udelay (10); + + if (!timeout--) { + printk ("rc_getmac: Timeout\n"); + return RC_RTN_MSG_REPLY_TIMEOUT; + } + } + + /* read the mac address */ + temp[0] = p_atu->EtherMacLow; + temp[1] = p_atu->EtherMacHi; + memcpy ((char *) mac, (char *) temp, 6); + + dprintk ("rc_getmac: 0x%x\n", (u32) mac); + + return RC_RTN_NO_ERROR; } - /* ** ========================================================================= ** RCSetMAC() @@ -889,37 +871,35 @@ RCGetMAC(struct net_device *dev, PFNWAITCALLBACK WaitCallback) ** ========================================================================= */ RC_RETURN -RCSetMAC(struct net_device *dev, PU8 mac) +RCSetMAC (struct net_device * dev, PU8 mac) { - U32 off; - PU32 pMsg; - PPAB pPab = ((PDPA)dev->priv)->pPab; - - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); - - /* setup private message */ - pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_MAC_ADDR; - pMsg[5] = *(unsigned *)mac; /* first four bytes */ - pMsg[6] = *(unsigned *)(mac + 4); /* last two bytes */ - - pPab->p_atu->InQueue = off; /* send it to the I2O device */ - - return RC_RTN_NO_ERROR ; -} + U32 off; + PU32 pMsg; + PPAB pPab = ((PDPA) dev->priv)->pPab; + + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; + + off = pPab->p_atu->InQueue; /* get addresss of message */ + + if (0xFFFFFFFF == off) + return RC_RTN_FREE_Q_EMPTY; + + pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); + + /* setup private message */ + pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x219; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_MAC_ADDR; + pMsg[5] = *(unsigned *) mac; /* first four bytes */ + pMsg[6] = *(unsigned *) (mac + 4); /* last two bytes */ + pPab->p_atu->InQueue = off; /* send it to the I2O device */ + + return RC_RTN_NO_ERROR; +} /* ** ========================================================================= @@ -936,35 +916,35 @@ RCSetMAC(struct net_device *dev, PU8 mac) ** ========================================================================= */ RC_RETURN -RCSetLinkSpeed(struct net_device *dev, U16 LinkSpeedCode) +RCSetLinkSpeed (struct net_device * dev, U16 LinkSpeedCode) { - U32 off; - PU32 pMsg; - PPAB pPab = ((PDPA)dev->priv)->pPab; - - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_LINK_SPEED; - pMsg[5] = LinkSpeedCode; /* link speed code */ - - pPab->p_atu->InQueue = off; /* send it to the I2O device */ - - return RC_RTN_NO_ERROR ; + U32 off; + PU32 pMsg; + PPAB pPab = ((PDPA) dev->priv)->pPab; + + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; + + off = pPab->p_atu->InQueue; /* get addresss of message */ + + if (0xFFFFFFFF == off) + return RC_RTN_FREE_Q_EMPTY; + + pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); + + /* setup private message */ + pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x219; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_LINK_SPEED; + pMsg[5] = LinkSpeedCode; /* link speed code */ + + pPab->p_atu->InQueue = off; /* send it to the I2O device */ + + return RC_RTN_NO_ERROR; } + /* ** ========================================================================= ** RCSetPromiscuousMode() @@ -976,34 +956,35 @@ RCSetLinkSpeed(struct net_device *dev, U16 LinkSpeedCode) ** ========================================================================= */ RC_RETURN -RCSetPromiscuousMode(struct net_device *dev, U16 Mode) +RCSetPromiscuousMode (struct net_device * dev, U16 Mode) { - U32 off; - PU32 pMsg; - PPAB pPab = ((PDPA)dev->priv)->pPab; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_PROMISCUOUS_MODE; - pMsg[5] = Mode; /* promiscuous mode setting */ - - pPab->p_atu->InQueue = off; /* send it to the device */ - - return RC_RTN_NO_ERROR ; + U32 off; + PU32 pMsg; + PPAB pPab = ((PDPA) dev->priv)->pPab; + + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; + + off = pPab->p_atu->InQueue; /* get addresss of message */ + + if (0xFFFFFFFF == off) + return RC_RTN_FREE_Q_EMPTY; + + pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); + + /* setup private message */ + pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x219; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_PROMISCUOUS_MODE; + pMsg[5] = Mode; /* promiscuous mode setting */ + + pPab->p_atu->InQueue = off; /* send it to the device */ + + return RC_RTN_NO_ERROR; } + /* ** ========================================================================= ** RCGetPromiscuousMode() @@ -1017,67 +998,67 @@ RCSetPromiscuousMode(struct net_device *dev, U16 Mode) ** ========================================================================= */ RC_RETURN -RCGetPromiscuousMode(struct net_device *dev, PU32 pMode, - PFNWAITCALLBACK WaitCallback) +RCGetPromiscuousMode (struct net_device * dev, PU32 pMode, + PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; - PPAB pPab = ((PDPA)dev->priv)->pPab; - - - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) - { - printk(KERN_WARNING "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); - - /* virtual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32)pPab->pLinOutMsgBlock; - p32[0] = 0xff; - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_PROMISCUOUS_MODE; - /* phys address to return status - area right after PAB */ - pMsg[5] = pPab->outMsgBlockPhyAddr; - - /* post to Inbound Post Q */ - - pPab->p_atu->InQueue = msgOffset; - - /* wait for response */ - timeout = 1000000; - while(1) { - if (WaitCallback) - (*WaitCallback)(); - - udelay(10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) - { - dprintk("Timeout waiting for promiscuous mode from adapter\n"); - dprintk("0x%8x\n", p32[0]); - return RC_RTN_NO_LINK_SPEED; - } - } - - /* get mode */ - *pMode = (U8)((volatile PU8)p32)[0] & 0x0f; - - return RC_RTN_NO_ERROR; + U32 msgOffset, timeout; + PU32 pMsg; + volatile PU32 p32; + PPAB pPab = ((PDPA) dev->priv)->pPab; + + msgOffset = pPab->p_atu->InQueue; + + if (msgOffset == 0xFFFFFFFF) { + printk (KERN_WARNING + "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); + return RC_RTN_FREE_Q_EMPTY; + } + + /* calc virtual address of msg - virtual already mapped to physical */ + pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); + + /* virtual pointer to return buffer - clear first two dwords */ + p32 = (volatile PU32) pPab->pLinOutMsgBlock; + p32[0] = 0xff; + + /* setup private message */ + pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x219; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_PROMISCUOUS_MODE; + /* phys address to return status - area right after PAB */ + pMsg[5] = pPab->outMsgBlockPhyAddr; + + /* post to Inbound Post Q */ + + pPab->p_atu->InQueue = msgOffset; + + /* wait for response */ + timeout = 1000000; + while (1) { + if (WaitCallback) + (*WaitCallback) (); + + udelay (10); /* please don't hog the bus!!! */ + + if (p32[0] != 0xff) + break; + + if (!timeout--) { + dprintk + ("Timeout waiting for promiscuous mode from adapter\n"); + dprintk ("0x%8x\n", p32[0]); + return RC_RTN_NO_LINK_SPEED; + } + } + + /* get mode */ + *pMode = (U8) ((volatile PU8) p32)[0] & 0x0f; + + return RC_RTN_NO_ERROR; } + /* ** ========================================================================= ** RCSetBroadcastMode() @@ -1089,35 +1070,35 @@ RCGetPromiscuousMode(struct net_device *dev, PU32 pMode, ** ========================================================================= */ RC_RETURN -RCSetBroadcastMode(struct net_device *dev, U16 Mode) +RCSetBroadcastMode (struct net_device * dev, U16 Mode) { - U32 off; - PU32 pMsg; - PPAB pPab = ((PDPA)dev->priv)->pPab; - - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_BROADCAST_MODE; - pMsg[5] = Mode; /* promiscuous mode setting */ - - pPab->p_atu->InQueue = off; /* send it to the device */ - - return RC_RTN_NO_ERROR ; + U32 off; + PU32 pMsg; + PPAB pPab = ((PDPA) dev->priv)->pPab; + + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; + + off = pPab->p_atu->InQueue; /* get addresss of message */ + + if (0xFFFFFFFF == off) + return RC_RTN_FREE_Q_EMPTY; + + pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); + + /* setup private message */ + pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x219; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_BROADCAST_MODE; + pMsg[5] = Mode; /* promiscuous mode setting */ + + pPab->p_atu->InQueue = off; /* send it to the device */ + + return RC_RTN_NO_ERROR; } + /* ** ========================================================================= ** RCGetBroadcastMode() @@ -1131,66 +1112,66 @@ RCSetBroadcastMode(struct net_device *dev, U16 Mode) ** ========================================================================= */ RC_RETURN -RCGetBroadcastMode(struct net_device *dev, PU32 pMode, - PFNWAITCALLBACK WaitCallback) +RCGetBroadcastMode (struct net_device * dev, PU32 pMode, + PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; - PPAB pPab = ((PDPA)dev->priv)->pPab; - - - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) - { - printk(KERN_WARNING "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); - - /* virtual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32)pPab->pLinOutMsgBlock; - p32[0] = 0xff; - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_BROADCAST_MODE; - /* phys address to return status - area right after PAB */ - pMsg[5] = pPab->outMsgBlockPhyAddr; - - /* post to Inbound Post Q */ - - pPab->p_atu->InQueue = msgOffset; - - /* wait for response */ - timeout = 1000000; - while(1) { - if (WaitCallback) - (*WaitCallback)(); - - udelay(10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) - { - printk(KERN_WARNING "(rcpci45 driver:) Timeout waiting for promiscuous mode from adapter\n"); - printk(KERN_WARNING "(rcpci45 driver:) 0x%8x\n", p32[0]); - return RC_RTN_NO_LINK_SPEED; - } - } - - /* get mode */ - *pMode = (U8)((volatile PU8)p32)[0] & 0x0f; - - return RC_RTN_NO_ERROR; + U32 msgOffset, timeout; + PU32 pMsg; + volatile PU32 p32; + PPAB pPab = ((PDPA) dev->priv)->pPab; + + msgOffset = pPab->p_atu->InQueue; + + if (msgOffset == 0xFFFFFFFF) { + printk (KERN_WARNING + "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); + return RC_RTN_FREE_Q_EMPTY; + } + + /* calc virtual address of msg - virtual already mapped to physical */ + pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); + + /* virtual pointer to return buffer - clear first two dwords */ + p32 = (volatile PU32) pPab->pLinOutMsgBlock; + p32[0] = 0xff; + + /* setup private message */ + pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x219; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_BROADCAST_MODE; + /* phys address to return status - area right after PAB */ + pMsg[5] = pPab->outMsgBlockPhyAddr; + + /* post to Inbound Post Q */ + + pPab->p_atu->InQueue = msgOffset; + + /* wait for response */ + timeout = 1000000; + while (1) { + if (WaitCallback) + (*WaitCallback) (); + + udelay (10); /* please don't hog the bus!!! */ + + if (p32[0] != 0xff) + break; + + if (!timeout--) { + printk (KERN_WARNING + "(rcpci45 driver:) Timeout waiting for promiscuous mode from adapter\n"); + printk (KERN_WARNING "(rcpci45 driver:) 0x%8x\n", + p32[0]); + return RC_RTN_NO_LINK_SPEED; + } + } + + /* get mode */ + *pMode = (U8) ((volatile PU8) p32)[0] & 0x0f; + + return RC_RTN_NO_ERROR; } /* @@ -1208,69 +1189,67 @@ RCGetBroadcastMode(struct net_device *dev, PU32 pMode, ** ========================================================================= */ RC_RETURN -RCGetLinkSpeed(struct net_device *dev, PU32 pLinkSpeedCode, - PFNWAITCALLBACK WaitCallback) +RCGetLinkSpeed (struct net_device * dev, PU32 pLinkSpeedCode, + PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; - U8 IOPLinkSpeed; - PPAB pPab = ((PDPA)dev->priv)->pPab; - - - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) - { - printk(KERN_WARNING "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); - - /* virtual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32)pPab->pLinOutMsgBlock; - p32[0] = 0xff; - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_SPEED; - /* phys address to return status - area right after PAB */ - pMsg[5] = pPab->outMsgBlockPhyAddr; - - /* post to Inbound Post Q */ - - pPab->p_atu->InQueue = msgOffset; - - /* wait for response */ - timeout = 1000000; - while(1) { - if (WaitCallback) - (*WaitCallback)(); - - udelay(10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) - { - dprintk("Timeout waiting for link speed from IOP\n"); - dprintk("0x%8x\n", p32[0]); - return RC_RTN_NO_LINK_SPEED; - } - } - - /* get Link speed */ - IOPLinkSpeed = (U8)((volatile PU8)p32)[0] & 0x0f; - - *pLinkSpeedCode= IOPLinkSpeed; - - return RC_RTN_NO_ERROR; + U32 msgOffset, timeout; + PU32 pMsg; + volatile PU32 p32; + U8 IOPLinkSpeed; + PPAB pPab = ((PDPA) dev->priv)->pPab; + + msgOffset = pPab->p_atu->InQueue; + + if (msgOffset == 0xFFFFFFFF) { + printk (KERN_WARNING + "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); + return RC_RTN_FREE_Q_EMPTY; + } + + /* calc virtual address of msg - virtual already mapped to physical */ + pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); + + /* virtual pointer to return buffer - clear first two dwords */ + p32 = (volatile PU32) pPab->pLinOutMsgBlock; + p32[0] = 0xff; + + /* setup private message */ + pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x219; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_SPEED; + /* phys address to return status - area right after PAB */ + pMsg[5] = pPab->outMsgBlockPhyAddr; + + /* post to Inbound Post Q */ + + pPab->p_atu->InQueue = msgOffset; + + /* wait for response */ + timeout = 1000000; + while (1) { + if (WaitCallback) + (*WaitCallback) (); + + udelay (10); /* please don't hog the bus!!! */ + + if (p32[0] != 0xff) + break; + + if (!timeout--) { + dprintk ("Timeout waiting for link speed from IOP\n"); + dprintk ("0x%8x\n", p32[0]); + return RC_RTN_NO_LINK_SPEED; + } + } + + /* get Link speed */ + IOPLinkSpeed = (U8) ((volatile PU8) p32)[0] & 0x0f; + + *pLinkSpeedCode = IOPLinkSpeed; + + return RC_RTN_NO_ERROR; } /* @@ -1283,33 +1262,34 @@ RCGetLinkSpeed(struct net_device *dev, PU32 pLinkSpeedCode, ** ========================================================================= */ RC_RETURN -RCReportDriverCapability(struct net_device *dev, U32 capability) +RCReportDriverCapability (struct net_device * dev, U32 capability) { - U32 off; - PU32 pMsg; - PPAB pPab = ((PDPA)dev->priv)->pPab; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_REPORT_DRIVER_CAPABILITY; - pMsg[5] = capability; - - pPab->p_atu->InQueue = off; /* send it to the I2O device */ - - return RC_RTN_NO_ERROR ; + U32 off; + PU32 pMsg; + PPAB pPab = ((PDPA) dev->priv)->pPab; + + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; + + off = pPab->p_atu->InQueue; /* get addresss of message */ + + if (0xFFFFFFFF == off) + return RC_RTN_FREE_Q_EMPTY; + + pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); + + /* setup private message */ + pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x219; /* transaction context */ + pMsg[4] = + RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_REPORT_DRIVER_CAPABILITY; + pMsg[5] = capability; + + pPab->p_atu->InQueue = off; /* send it to the I2O device */ + + return RC_RTN_NO_ERROR; } /* @@ -1321,65 +1301,59 @@ RCReportDriverCapability(struct net_device *dev, U32 capability) ** ========================================================================= */ RC_RETURN -RCGetFirmwareVer(struct net_device *dev, PU8 pFirmString, - PFNWAITCALLBACK WaitCallback) +RCGetFirmwareVer (struct net_device * dev, PU8 pFirmString, + PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; - PPAB pPab = ((PDPA)dev->priv)->pPab; - - - msgOffset = pPab->p_atu->InQueue; - if (msgOffset == 0xFFFFFFFF) - { - dprintk("RCGetFirmwareVer(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); - - /* virtual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32)pPab->pLinOutMsgBlock; - p32[0] = 0xff; - - /* setup private message */ - pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_FIRMWARE_REV; - /* phys address to return status - area right after PAB */ - pMsg[5] = pPab->outMsgBlockPhyAddr; - - - - /* post to Inbound Post Q */ - - pPab->p_atu->InQueue = msgOffset; - - - /* wait for response */ - timeout = 1000000; - while(1) { - if (WaitCallback) - (*WaitCallback)(); - - udelay(10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) - { - dprintk("Timeout waiting for link speed from IOP\n"); - return RC_RTN_NO_FIRM_VER; - } - } - - strcpy(pFirmString, (PU8)p32); - return RC_RTN_NO_ERROR; + U32 msgOffset, timeout; + PU32 pMsg; + volatile PU32 p32; + PPAB pPab = ((PDPA) dev->priv)->pPab; + + msgOffset = pPab->p_atu->InQueue; + if (msgOffset == 0xFFFFFFFF) { + dprintk ("RCGetFirmwareVer(): Inbound Free Q empty!\n"); + return RC_RTN_FREE_Q_EMPTY; + } + + /* calc virtual address of msg - virtual already mapped to physical */ + pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); + + /* virtual pointer to return buffer - clear first two dwords */ + p32 = (volatile PU32) pPab->pLinOutMsgBlock; + p32[0] = 0xff; + + /* setup private message */ + pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x219; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_FIRMWARE_REV; + /* phys address to return status - area right after PAB */ + pMsg[5] = pPab->outMsgBlockPhyAddr; + + /* post to Inbound Post Q */ + + pPab->p_atu->InQueue = msgOffset; + + /* wait for response */ + timeout = 1000000; + while (1) { + if (WaitCallback) + (*WaitCallback) (); + + udelay (10); /* please don't hog the bus!!! */ + + if (p32[0] != 0xff) + break; + + if (!timeout--) { + dprintk ("Timeout waiting for link speed from IOP\n"); + return RC_RTN_NO_FIRM_VER; + } + } + + strcpy (pFirmString, (PU8) p32); + return RC_RTN_NO_ERROR; } /* @@ -1395,56 +1369,53 @@ RCGetFirmwareVer(struct net_device *dev, PU8 pFirmString, ** ** ========================================================================= */ -RC_RETURN -RCResetLANCard(struct net_device *dev, U16 ResourceFlags, PU32 ReturnAddr, - PFNCALLBACK CallbackFunction) +RC_RETURN +RCResetLANCard (struct net_device * dev, U16 ResourceFlags, PU32 ReturnAddr, + PFNCALLBACK CallbackFunction) { - unsigned long off; - PU32 pMsg; - PPAB pPab = ((PDPA)dev->priv)->pPab; - long timeout = 0; - - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pPab->pCallbackFunc = CallbackFunction; - - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); - - /* setup message */ - pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_LAN_RESET << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = ResourceFlags << 16; /* resource flags */ - - pPab->p_atu->InQueue = off; /* send it to the I2O device */ - - if (CallbackFunction == (PFNCALLBACK)NULL) - { - /* call RCProcI2OMsgQ() until something in pPab->pCallbackFunc - or until timer goes off */ - while (pPab->pCallbackFunc == (PFNCALLBACK)NULL) - { - RCProcI2OMsgQ(dev); - udelay(1000); /* please don't hog the bus!!! */ - timeout++; - if (timeout > 10000) - { - break; - } - } - if (ReturnAddr != (PU32)NULL) - *ReturnAddr = (U32)pPab->pCallbackFunc; - } - - return RC_RTN_NO_ERROR ; + unsigned long off; + PU32 pMsg; + PPAB pPab = ((PDPA) dev->priv)->pPab; + long timeout = 0; + + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; + + off = pPab->p_atu->InQueue; /* get addresss of message */ + + if (0xFFFFFFFF == off) + return RC_RTN_FREE_Q_EMPTY; + + pPab->pCallbackFunc = CallbackFunction; + + pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); + + /* setup message */ + pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_LAN_RESET << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; + pMsg[3] = ResourceFlags << 16; /* resource flags */ + + pPab->p_atu->InQueue = off; /* send it to the I2O device */ + + if (CallbackFunction == (PFNCALLBACK) NULL) { + /* call RCProcI2OMsgQ() until something in pPab->pCallbackFunc + or until timer goes off */ + while (pPab->pCallbackFunc == (PFNCALLBACK) NULL) { + RCProcI2OMsgQ (dev); + udelay (1000); /* please don't hog the bus!!! */ + timeout++; + if (timeout > 10000) { + break; + } + } + if (ReturnAddr != (PU32) NULL) + *ReturnAddr = (U32) pPab->pCallbackFunc; + } + + return RC_RTN_NO_ERROR; } + /* ** ========================================================================= ** RCResetIOP() @@ -1453,59 +1424,57 @@ RCResetLANCard(struct net_device *dev, U16 ResourceFlags, PU32 ReturnAddr, ** ** ========================================================================= */ -RC_RETURN -RCResetIOP(struct net_device *dev) +RC_RETURN +RCResetIOP (struct net_device * dev) { - U32 msgOffset, timeout; - PU32 pMsg; - PPAB pPab = ((PDPA)dev->priv)->pPab; - volatile PU32 p32; - - msgOffset = pPab->p_atu->InQueue; - - if (msgOffset == 0xFFFFFFFF) - { - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); - - pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_EXEC_IOP_RESET << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID; - pMsg[2] = 0; /* universal context */ - pMsg[3] = 0; /* universal context */ - pMsg[4] = 0; /* universal context */ - pMsg[5] = 0; /* universal context */ - /* phys address to return status - area right after PAB */ - pMsg[6] = pPab->outMsgBlockPhyAddr; - pMsg[7] = 0; - pMsg[8] = 1; /* return 1 byte */ - - /* virual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32)pPab->pLinOutMsgBlock; - p32[0] = 0; - p32[1] = 0; - - /* post to Inbound Post Q */ - - pPab->p_atu->InQueue = msgOffset; - - /* wait for response */ - timeout = 1000000; - while(1) { - udelay(10); /* please don't hog the bus!!! */ - - if (p32[0] || p32[1]) - break; - - if (!timeout--) - { - dprintk("RCResetIOP timeout\n"); - return RC_RTN_MSG_REPLY_TIMEOUT; - } - } - return RC_RTN_NO_ERROR; + U32 msgOffset, timeout; + PU32 pMsg; + PPAB pPab = ((PDPA) dev->priv)->pPab; + volatile PU32 p32; + + msgOffset = pPab->p_atu->InQueue; + + if (msgOffset == 0xFFFFFFFF) { + return RC_RTN_FREE_Q_EMPTY; + } + + /* calc virtual address of msg - virtual already mapped to physical */ + pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); + + pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_EXEC_IOP_RESET << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID; + pMsg[2] = 0; /* universal context */ + pMsg[3] = 0; /* universal context */ + pMsg[4] = 0; /* universal context */ + pMsg[5] = 0; /* universal context */ + /* phys address to return status - area right after PAB */ + pMsg[6] = pPab->outMsgBlockPhyAddr; + pMsg[7] = 0; + pMsg[8] = 1; /* return 1 byte */ + + /* virual pointer to return buffer - clear first two dwords */ + p32 = (volatile PU32) pPab->pLinOutMsgBlock; + p32[0] = 0; + p32[1] = 0; + + /* post to Inbound Post Q */ + + pPab->p_atu->InQueue = msgOffset; + + /* wait for response */ + timeout = 1000000; + while (1) { + udelay (10); /* please don't hog the bus!!! */ + + if (p32[0] || p32[1]) + break; + + if (!timeout--) { + dprintk ("RCResetIOP timeout\n"); + return RC_RTN_MSG_REPLY_TIMEOUT; + } + } + return RC_RTN_NO_ERROR; } /* @@ -1521,57 +1490,55 @@ RCResetIOP(struct net_device *dev) ** ** ========================================================================= */ -RC_RETURN -RCShutdownLANCard(struct net_device *dev, U16 ResourceFlags, - PU32 ReturnAddr, PFNCALLBACK CallbackFunction) +RC_RETURN +RCShutdownLANCard (struct net_device * dev, U16 ResourceFlags, + PU32 ReturnAddr, PFNCALLBACK CallbackFunction) { - volatile PU32 pMsg; - U32 off; - PPAB pPab = ((PDPA)dev->priv)->pPab; - long timeout = 0; - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pPab->pCallbackFunc = CallbackFunction; - - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); - - /* setup message */ - pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_LAN_SHUTDOWN << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = ResourceFlags << 16; /* resource flags */ - - pPab->p_atu->InQueue = off; /* send it to the I2O device */ - - if (CallbackFunction == (PFNCALLBACK)NULL) - { - /* call RCProcI2OMsgQ() until something in pPab->pCallbackFunc - or until timer goes off */ - while (pPab->pCallbackFunc == (PFNCALLBACK)NULL) - { - RCProcI2OMsgQ(dev); - udelay(1000); /* please don't hog the bus!!! */ - timeout++; - if (timeout > 10000) - { - printk(KERN_WARNING "(rcpci45 driver:) RCShutdownLANCard(): timeout\n"); - break; - } - } - if (ReturnAddr != (PU32)NULL) - *ReturnAddr = (U32)pPab->pCallbackFunc; - } - return RC_RTN_NO_ERROR ; + volatile PU32 pMsg; + U32 off; + PPAB pPab = ((PDPA) dev->priv)->pPab; + long timeout = 0; + + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; + + off = pPab->p_atu->InQueue; /* get addresss of message */ + + if (0xFFFFFFFF == off) + return RC_RTN_FREE_Q_EMPTY; + + pPab->pCallbackFunc = CallbackFunction; + + pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); + + /* setup message */ + pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = + I2O_LAN_SHUTDOWN << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; + pMsg[3] = ResourceFlags << 16; /* resource flags */ + + pPab->p_atu->InQueue = off; /* send it to the I2O device */ + + if (CallbackFunction == (PFNCALLBACK) NULL) { + /* call RCProcI2OMsgQ() until something in pPab->pCallbackFunc + or until timer goes off */ + while (pPab->pCallbackFunc == (PFNCALLBACK) NULL) { + RCProcI2OMsgQ (dev); + udelay (1000); /* please don't hog the bus!!! */ + timeout++; + if (timeout > 10000) { + printk (KERN_WARNING + "(rcpci45 driver:) RCShutdownLANCard(): timeout\n"); + break; + } + } + if (ReturnAddr != (PU32) NULL) + *ReturnAddr = (U32) pPab->pCallbackFunc; + } + return RC_RTN_NO_ERROR; } - /* ** ========================================================================= ** RCSetRavlinIPandMask() @@ -1585,34 +1552,33 @@ RCShutdownLANCard(struct net_device *dev, U16 ResourceFlags, ** ========================================================================= */ RC_RETURN -RCSetRavlinIPandMask(struct net_device *dev, U32 ipAddr, U32 netMask) +RCSetRavlinIPandMask (struct net_device * dev, U32 ipAddr, U32 netMask) { - volatile PU32 pMsg; - U32 off; - PPAB pPab = ((PDPA)dev->priv)->pPab; + volatile PU32 pMsg; + U32 off; + PPAB pPab = ((PDPA) dev->priv)->pPab; + + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; + off = pPab->p_atu->InQueue; /* get addresss of message */ - off = pPab->p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); + if (0xFFFFFFFF == off) + return RC_RTN_FREE_Q_EMPTY; - /* setup private message */ - pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x219; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_IP_AND_MASK; - pMsg[5] = ipAddr; - pMsg[6] = netMask; + pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); + /* setup private message */ + pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x219; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_IP_AND_MASK; + pMsg[5] = ipAddr; + pMsg[6] = netMask; - pPab->p_atu->InQueue = off; /* send it to the I2O device */ - return RC_RTN_NO_ERROR ; + pPab->p_atu->InQueue = off; /* send it to the I2O device */ + return RC_RTN_NO_ERROR; } @@ -1625,69 +1591,76 @@ RCSetRavlinIPandMask(struct net_device *dev, U32 ipAddr, U32 netMask) ** ========================================================================= */ RC_RETURN -RCGetRavlinIPandMask(struct net_device *dev, PU32 pIpAddr, PU32 pNetMask, - PFNWAITCALLBACK WaitCallback) +RCGetRavlinIPandMask (struct net_device * dev, PU32 pIpAddr, PU32 pNetMask, + PFNWAITCALLBACK WaitCallback) { - unsigned timeout; - U32 off; - PU32 pMsg, p32; - PPAB pPab = ((PDPA)dev->priv)->pPab; - PATU p_atu; - - dprintk("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n", (u32)pIpAddr, *pIpAddr); - - if (pPab == NULL) - return RC_RTN_ADPTR_NOT_REGISTERED; - - p_atu = pPab->p_atu; - off = p_atu->InQueue; /* get addresss of message */ - - if (0xFFFFFFFF == off) - return RC_RTN_FREE_Q_EMPTY; - - p32 = (volatile PU32)pPab->pLinOutMsgBlock; - *p32 = 0xFFFFFFFF; - - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); - - dprintk("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n", (u32)p_atu, off, (u32)p32); - /* setup private message */ - pMsg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; - pMsg[2] = 0; /* initiator context */ - pMsg[3] = 0x218; /* transaction context */ - pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_IP_AND_MASK; - pMsg[5] = pPab->outMsgBlockPhyAddr; - - p_atu->InQueue = off; /* send it to the I2O device */ - dprintk("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n", (u32)p_atu, off, (u32)p32); - - /* wait for the rcpci45 board to update the info */ - timeout = 100000; - while (0xffffffff == *p32) - { - if (WaitCallback) - (*WaitCallback)(); - - udelay(10); - - if (!timeout--) - { - dprintk("RCGetRavlinIPandMask: Timeout\n"); - return RC_RTN_MSG_REPLY_TIMEOUT; - } - } - - dprintk("RCGetRavlinIPandMask: after time out\np32[0] (IpAddr) 0x%08ulx, p32[1] (IPmask) 0x%08ulx\n", p32[0], p32[1]); - - /* send IP and mask to user's space */ - *pIpAddr = p32[0]; - *pNetMask = p32[1]; - - - dprintk("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n", (u32)pIpAddr, *pIpAddr); - - return RC_RTN_NO_ERROR; + unsigned timeout; + U32 off; + PU32 pMsg, p32; + PPAB pPab = ((PDPA) dev->priv)->pPab; + PATU p_atu; + + dprintk + ("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n", + (u32) pIpAddr, *pIpAddr); + + if (pPab == NULL) + return RC_RTN_ADPTR_NOT_REGISTERED; + + p_atu = pPab->p_atu; + off = p_atu->InQueue; /* get addresss of message */ + + if (0xFFFFFFFF == off) + return RC_RTN_FREE_Q_EMPTY; + + p32 = (volatile PU32) pPab->pLinOutMsgBlock; + *p32 = 0xFFFFFFFF; + + pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); + + dprintk + ("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n", + (u32) p_atu, off, (u32) p32); + /* setup private message */ + pMsg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; + pMsg[2] = 0; /* initiator context */ + pMsg[3] = 0x218; /* transaction context */ + pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_IP_AND_MASK; + pMsg[5] = pPab->outMsgBlockPhyAddr; + + p_atu->InQueue = off; /* send it to the I2O device */ + dprintk + ("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n", + (u32) p_atu, off, (u32) p32); + + /* wait for the rcpci45 board to update the info */ + timeout = 100000; + while (0xffffffff == *p32) { + if (WaitCallback) + (*WaitCallback) (); + + udelay (10); + + if (!timeout--) { + dprintk ("RCGetRavlinIPandMask: Timeout\n"); + return RC_RTN_MSG_REPLY_TIMEOUT; + } + } + + dprintk + ("RCGetRavlinIPandMask: after time out\np32[0] (IpAddr) 0x%08ulx, p32[1] (IPmask) 0x%08ulx\n", + p32[0], p32[1]); + + /* send IP and mask to user's space */ + *pIpAddr = p32[0]; + *pNetMask = p32[1]; + + dprintk + ("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n", + (u32) pIpAddr, *pIpAddr); + + return RC_RTN_NO_ERROR; } /* @@ -1706,90 +1679,84 @@ RCGetRavlinIPandMask(struct net_device *dev, PU32 pIpAddr, PU32 pNetMask, ** ** ========================================================================= */ -static int -SendI2OOutboundQInitMsg(PPAB pPab) +static int +SendI2OOutboundQInitMsg (PPAB pPab) { - U32 msgOffset, timeout, phyOutQFrames, i; - volatile PU32 pMsg; - volatile PU32 p32; - - - - msgOffset = pPab->p_atu->InQueue; - - - if (msgOffset == 0xFFFFFFFF) - { - dprintk("SendI2OOutboundQInitMsg(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - - /* calc virual address of msg - virual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); - - dprintk("SendI2OOutboundQInitMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", (u32)pMsg, msgOffset); - - pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6; - pMsg[1] = I2O_EXEC_OUTBOUND_INIT << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID; - pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = 0x106; /* transaction context */ - pMsg[4] = 4096; /* Host page frame size */ - pMsg[5] = MSG_FRAME_SIZE << 16 | 0x80; /* outbound msg frame size and Initcode */ - pMsg[6] = 0xD0000004; /* simple sgl element LE, EOB */ - /* phys address to return status - area right after PAB */ - pMsg[7] = pPab->outMsgBlockPhyAddr; - - /* virual pointer to return buffer - clear first two dwords */ - p32 = (PU32)pPab->pLinOutMsgBlock; - p32[0] = 0; - - /* post to Inbound Post Q */ - pPab->p_atu->InQueue = msgOffset; - - /* wait for response */ - timeout = 100000; - while(1) - { - udelay(10); /* please don't hog the bus!!! */ - - if (p32[0]) - break; - - if (!timeout--) - { - dprintk("Timeout wait for InitOutQ InPrgress status from IOP\n"); - return RC_RTN_NO_I2O_STATUS; - } - } - - timeout = 100000; - while(1) - { - udelay(10); /* please don't hog the bus!!! */ - - if (p32[0] == I2O_EXEC_OUTBOUND_INIT_COMPLETE) - break; - - if (!timeout--) - { - dprintk("Timeout wait for InitOutQ Complete status from IOP\n"); - return RC_RTN_NO_I2O_STATUS; - } - } - - /* load PCI outbound free Q with MF physical addresses */ - phyOutQFrames = pPab->outMsgBlockPhyAddr; - - for (i = 0; i < NMBR_MSG_FRAMES; i++) - { - pPab->p_atu->OutQueue = phyOutQFrames; - phyOutQFrames += MSG_FRAME_SIZE; - } - return RC_RTN_NO_ERROR; + U32 msgOffset, timeout, phyOutQFrames, i; + volatile PU32 pMsg; + volatile PU32 p32; + + msgOffset = pPab->p_atu->InQueue; + + if (msgOffset == 0xFFFFFFFF) { + dprintk ("SendI2OOutboundQInitMsg(): Inbound Free Q empty!\n"); + return RC_RTN_FREE_Q_EMPTY; + } + + /* calc virual address of msg - virual already mapped to physical */ + pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); + + dprintk + ("SendI2OOutboundQInitMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", + (u32) pMsg, msgOffset); + + pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6; + pMsg[1] = + I2O_EXEC_OUTBOUND_INIT << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID; + pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; + pMsg[3] = 0x106; /* transaction context */ + pMsg[4] = 4096; /* Host page frame size */ + pMsg[5] = MSG_FRAME_SIZE << 16 | 0x80; /* outbound msg frame size and Initcode */ + pMsg[6] = 0xD0000004; /* simple sgl element LE, EOB */ + /* phys address to return status - area right after PAB */ + pMsg[7] = pPab->outMsgBlockPhyAddr; + + /* virual pointer to return buffer - clear first two dwords */ + p32 = (PU32) pPab->pLinOutMsgBlock; + p32[0] = 0; + + /* post to Inbound Post Q */ + pPab->p_atu->InQueue = msgOffset; + + /* wait for response */ + timeout = 100000; + while (1) { + udelay (10); /* please don't hog the bus!!! */ + + if (p32[0]) + break; + + if (!timeout--) { + dprintk + ("Timeout wait for InitOutQ InPrgress status from IOP\n"); + return RC_RTN_NO_I2O_STATUS; + } + } + + timeout = 100000; + while (1) { + udelay (10); /* please don't hog the bus!!! */ + + if (p32[0] == I2O_EXEC_OUTBOUND_INIT_COMPLETE) + break; + + if (!timeout--) { + dprintk + ("Timeout wait for InitOutQ Complete status from IOP\n"); + return RC_RTN_NO_I2O_STATUS; + } + } + + /* load PCI outbound free Q with MF physical addresses */ + phyOutQFrames = pPab->outMsgBlockPhyAddr; + + for (i = 0; i < NMBR_MSG_FRAMES; i++) { + pPab->p_atu->OutQueue = phyOutQFrames; + phyOutQFrames += MSG_FRAME_SIZE; + } + return RC_RTN_NO_ERROR; } - /* ** ========================================================================= ** GetI2OStatus() @@ -1798,80 +1765,83 @@ SendI2OOutboundQInitMsg(PPAB pPab) ** ** ========================================================================= */ -static int -GetI2OStatus(PPAB pPab) +static int +GetI2OStatus (PPAB pPab) { - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; - - - msgOffset = pPab->p_atu->InQueue; - dprintk("GetI2OStatus: msg offset = 0x%x\n", msgOffset); - if (msgOffset == 0xFFFFFFFF) - { - dprintk("GetI2OStatus(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } - - /* calc virual address of msg - virual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); - - pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_EXEC_STATUS_GET << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID; - pMsg[2] = 0; /* universal context */ - pMsg[3] = 0; /* universal context */ - pMsg[4] = 0; /* universal context */ - pMsg[5] = 0; /* universal context */ - /* phys address to return status - area right after PAB */ - pMsg[6] = pPab->outMsgBlockPhyAddr; - pMsg[7] = 0; - pMsg[8] = 88; /* return 88 bytes */ - - /* virual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32)pPab->pLinOutMsgBlock; - p32[0] = 0; - p32[1] = 0; - - dprintk("GetI2OStatus - pMsg:0x%08ulx, msgOffset:0x%08ulx, [1]:0x%08ulx, [6]:0x%08ulx\n", - (u32)pMsg, msgOffset, pMsg[1], pMsg[6]); - - /* post to Inbound Post Q */ - pPab->p_atu->InQueue = msgOffset; - - dprintk("Return status to p32 = 0x%08ulx\n", (u32)p32); - - /* wait for response */ - timeout = 1000000; - while(1) { - udelay(10); /* please don't hog the bus!!! */ - - if (p32[0] && p32[1]) - break; - - if (!timeout--) - { - dprintk("Timeout waiting for status from IOP\n"); - dprintk("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], p32[2], p32[3]); - dprintk("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], p32[6], p32[7]); - dprintk("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[8], p32[9], p32[10], p32[11]); - return RC_RTN_NO_I2O_STATUS; - } - } - - dprintk("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], p32[2], p32[3]); - dprintk("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], p32[6], p32[7]); - dprintk("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[8], p32[9], p32[10], p32[11]); - /* get IOP state */ - pPab->IOPState = ((volatile PU8)p32)[10]; - pPab->InboundMFrameSize = ((volatile PU16)p32)[6]; - - dprintk("IOP state 0x%02x InFrameSize = 0x%04x\n", - pPab->IOPState, pPab->InboundMFrameSize); - return RC_RTN_NO_ERROR; + U32 msgOffset, timeout; + PU32 pMsg; + volatile PU32 p32; + + msgOffset = pPab->p_atu->InQueue; + dprintk ("GetI2OStatus: msg offset = 0x%x\n", msgOffset); + if (msgOffset == 0xFFFFFFFF) { + dprintk ("GetI2OStatus(): Inbound Free Q empty!\n"); + return RC_RTN_FREE_Q_EMPTY; + } + + /* calc virual address of msg - virual already mapped to physical */ + pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); + + pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_EXEC_STATUS_GET << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID; + pMsg[2] = 0; /* universal context */ + pMsg[3] = 0; /* universal context */ + pMsg[4] = 0; /* universal context */ + pMsg[5] = 0; /* universal context */ + /* phys address to return status - area right after PAB */ + pMsg[6] = pPab->outMsgBlockPhyAddr; + pMsg[7] = 0; + pMsg[8] = 88; /* return 88 bytes */ + + /* virual pointer to return buffer - clear first two dwords */ + p32 = (volatile PU32) pPab->pLinOutMsgBlock; + p32[0] = 0; + p32[1] = 0; + + dprintk + ("GetI2OStatus - pMsg:0x%08ulx, msgOffset:0x%08ulx, [1]:0x%08ulx, [6]:0x%08ulx\n", + (u32) pMsg, msgOffset, pMsg[1], pMsg[6]); + + /* post to Inbound Post Q */ + pPab->p_atu->InQueue = msgOffset; + + dprintk ("Return status to p32 = 0x%08ulx\n", (u32) p32); + + /* wait for response */ + timeout = 1000000; + while (1) { + udelay (10); /* please don't hog the bus!!! */ + + if (p32[0] && p32[1]) + break; + + if (!timeout--) { + dprintk ("Timeout waiting for status from IOP\n"); + dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + p32[0], p32[1], p32[2], p32[3]); + dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + p32[4], p32[5], p32[6], p32[7]); + dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + p32[8], p32[9], p32[10], p32[11]); + return RC_RTN_NO_I2O_STATUS; + } + } + + dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], + p32[2], p32[3]); + dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], + p32[6], p32[7]); + dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[8], p32[9], + p32[10], p32[11]); + /* get IOP state */ + pPab->IOPState = ((volatile PU8) p32)[10]; + pPab->InboundMFrameSize = ((volatile PU16) p32)[6]; + + dprintk ("IOP state 0x%02x InFrameSize = 0x%04x\n", + pPab->IOPState, pPab->InboundMFrameSize); + return RC_RTN_NO_ERROR; } - /* ** ========================================================================= ** SendEnableSysMsg() @@ -1879,38 +1849,38 @@ GetI2OStatus(PPAB pPab) ** ** ========================================================================= */ -static int -SendEnableSysMsg(PPAB pPab) +static int +SendEnableSysMsg (PPAB pPab) { - U32 msgOffset; - volatile PU32 pMsg; + U32 msgOffset; + volatile PU32 pMsg; - msgOffset = pPab->p_atu->InQueue; + msgOffset = pPab->p_atu->InQueue; - if (msgOffset == 0xFFFFFFFF) - { - dprintk("SendEnableSysMsg(): Inbound Free Q empty!\n"); - return RC_RTN_FREE_Q_EMPTY; - } + if (msgOffset == 0xFFFFFFFF) { + dprintk ("SendEnableSysMsg(): Inbound Free Q empty!\n"); + return RC_RTN_FREE_Q_EMPTY; + } - /* calc virual address of msg - virual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + /* calc virual address of msg - virual already mapped to physical */ + pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); - dprintk("SendEnableSysMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", (u32)pMsg, msgOffset); + dprintk + ("SendEnableSysMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", + (u32) pMsg, msgOffset); - pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0; - pMsg[1] = I2O_EXEC_SYS_ENABLE << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID; - pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = 0x110; /* transaction context */ - pMsg[4] = 0x50657465; /* RedCreek Private */ + pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0; + pMsg[1] = I2O_EXEC_SYS_ENABLE << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID; + pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; + pMsg[3] = 0x110; /* transaction context */ + pMsg[4] = 0x50657465; /* RedCreek Private */ - /* post to Inbound Post Q */ - pPab->p_atu->InQueue = msgOffset; + /* post to Inbound Post Q */ + pPab->p_atu->InQueue = msgOffset; - return RC_RTN_NO_ERROR; + return RC_RTN_NO_ERROR; } - /* ** ========================================================================= ** FillI2OMsgFromTCB() @@ -1921,91 +1891,82 @@ SendEnableSysMsg(PPAB pPab) ** fills in LAN SGL after Transaction Control Word or Bucket Count. ** ========================================================================= */ -static int -FillI2OMsgSGLFromTCB(PU32 pMsgFrame, PRCTCB pTransCtrlBlock) +static int +FillI2OMsgSGLFromTCB (PU32 pMsgFrame, PRCTCB pTransCtrlBlock) { - unsigned int nmbrBuffers, nmbrSeg, nmbrDwords, context, flags; - PU32 pTCB, pMsg; + unsigned int nmbrBuffers, nmbrSeg, nmbrDwords, context, flags; + PU32 pTCB, pMsg; - /* SGL element flags */ + /* SGL element flags */ #define EOB 0x40000000 #define LE 0x80000000 #define SIMPLE_SGL 0x10000000 #define BC_PRESENT 0x01000000 - pTCB = (PU32)pTransCtrlBlock; - pMsg = pMsgFrame; - nmbrDwords = 0; - - dprintk("FillI2OMsgSGLFromTCBX\n"); - dprintk("TCB 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]); - dprintk("pTCB 0x%08ulx, pMsg 0x%08ulx\n", (u32)pTCB, (u32)pMsg); - - nmbrBuffers = *pTCB++; - - if (!nmbrBuffers) - { - return -1; - } - - do - { - context = *pTCB++; /* buffer tag (context) */ - nmbrSeg = *pTCB++; /* number of segments */ - - if (!nmbrSeg) - { - return -1; - } - - flags = SIMPLE_SGL | BC_PRESENT; - - if (1 == nmbrSeg) - { - flags |= EOB; - - if (1 == nmbrBuffers) - flags |= LE; - } - - /* 1st SGL buffer element has context */ - pMsg[0] = pTCB[0] | flags ; /* send over count (segment size) */ - pMsg[1] = context; - pMsg[2] = pTCB[1]; /* send buffer segment physical address */ - nmbrDwords += 3; - pMsg += 3; - pTCB += 2; - - - if (--nmbrSeg) - { - do - { - flags = SIMPLE_SGL; - - if (1 == nmbrSeg) - { - flags |= EOB; - - if (1 == nmbrBuffers) - flags |= LE; - } - - pMsg[0] = pTCB[0] | flags; /* send over count */ - pMsg[1] = pTCB[1]; /* send buffer segment physical address */ - nmbrDwords += 2; - pTCB += 2; - pMsg += 2; - - } while (--nmbrSeg); - } - - } while (--nmbrBuffers); - - return nmbrDwords; -} + pTCB = (PU32) pTransCtrlBlock; + pMsg = pMsgFrame; + nmbrDwords = 0; + + dprintk ("FillI2OMsgSGLFromTCBX\n"); + dprintk ("TCB 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]); + dprintk ("pTCB 0x%08ulx, pMsg 0x%08ulx\n", (u32) pTCB, (u32) pMsg); + + nmbrBuffers = *pTCB++; + + if (!nmbrBuffers) { + return -1; + } + + do { + context = *pTCB++; /* buffer tag (context) */ + nmbrSeg = *pTCB++; /* number of segments */ + + if (!nmbrSeg) { + return -1; + } + + flags = SIMPLE_SGL | BC_PRESENT; + + if (1 == nmbrSeg) { + flags |= EOB; + + if (1 == nmbrBuffers) + flags |= LE; + } + /* 1st SGL buffer element has context */ + pMsg[0] = pTCB[0] | flags; /* send over count (segment size) */ + pMsg[1] = context; + pMsg[2] = pTCB[1]; /* send buffer segment physical address */ + nmbrDwords += 3; + pMsg += 3; + pTCB += 2; + + if (--nmbrSeg) { + do { + flags = SIMPLE_SGL; + + if (1 == nmbrSeg) { + flags |= EOB; + + if (1 == nmbrBuffers) + flags |= LE; + } + + pMsg[0] = pTCB[0] | flags; /* send over count */ + pMsg[1] = pTCB[1]; /* send buffer segment physical address */ + nmbrDwords += 2; + pTCB += 2; + pMsg += 2; + + } while (--nmbrSeg); + } + + } while (--nmbrBuffers); + + return nmbrDwords; +} /* ** ========================================================================= @@ -2015,51 +1976,52 @@ FillI2OMsgSGLFromTCB(PU32 pMsgFrame, PRCTCB pTransCtrlBlock) ** * change to msg structure * ** ========================================================================= */ -static void -ProcessOutboundI2OMsg(PPAB pPab, U32 phyAddrMsg) +static void +ProcessOutboundI2OMsg (PPAB pPab, U32 phyAddrMsg) { - PU8 p8Msg; - PU32 p32; + PU8 p8Msg; + PU32 p32; /* U16 count; */ - - - p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr); - p32 = (PU32)p8Msg; - - dprintk("VXD: ProcessOutboundI2OMsg - pPab 0x%08ulx, phyAdr 0x%08ulx, linAdr 0x%08ulx\n", (u32)pPab, phyAddrMsg, (u32)p8Msg); - dprintk("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], p32[2], p32[3]); - dprintk("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], p32[6], p32[7]); - - if (p32[4] >> 24 != I2O_REPLY_STATUS_SUCCESS) - { - dprintk("Message reply status not success\n"); - return; - } - - switch (p8Msg[7] ) /* function code byte */ - { - case I2O_EXEC_SYS_TAB_SET: - msgFlag = 1; - dprintk("Received I2O_EXEC_SYS_TAB_SET reply\n"); - break; - - case I2O_EXEC_HRT_GET: - msgFlag = 1; - dprintk("Received I2O_EXEC_HRT_GET reply\n"); - break; - - case I2O_EXEC_LCT_NOTIFY: - msgFlag = 1; - dprintk("Received I2O_EXEC_LCT_NOTIFY reply\n"); - break; - - case I2O_EXEC_SYS_ENABLE: - msgFlag = 1; - dprintk("Received I2O_EXEC_SYS_ENABLE reply\n"); - break; - - default: - dprintk("Received UNKNOWN reply\n"); - break; - } + + p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr); + p32 = (PU32) p8Msg; + + dprintk + ("VXD: ProcessOutboundI2OMsg - pPab 0x%08ulx, phyAdr 0x%08ulx, linAdr 0x%08ulx\n", + (u32) pPab, phyAddrMsg, (u32) p8Msg); + dprintk ("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], + p32[2], p32[3]); + dprintk ("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], + p32[6], p32[7]); + + if (p32[4] >> 24 != I2O_REPLY_STATUS_SUCCESS) { + dprintk ("Message reply status not success\n"); + return; + } + + switch (p8Msg[7]) { /* function code byte */ + case I2O_EXEC_SYS_TAB_SET: + msgFlag = 1; + dprintk ("Received I2O_EXEC_SYS_TAB_SET reply\n"); + break; + + case I2O_EXEC_HRT_GET: + msgFlag = 1; + dprintk ("Received I2O_EXEC_HRT_GET reply\n"); + break; + + case I2O_EXEC_LCT_NOTIFY: + msgFlag = 1; + dprintk ("Received I2O_EXEC_LCT_NOTIFY reply\n"); + break; + + case I2O_EXEC_SYS_ENABLE: + msgFlag = 1; + dprintk ("Received I2O_EXEC_SYS_ENABLE reply\n"); + break; + + default: + dprintk ("Received UNKNOWN reply\n"); + break; + } } diff --git a/drivers/net/rclanmtl.h b/drivers/net/rclanmtl.h index 61d1a9cb268d..a65c1d94a83b 100644 --- a/drivers/net/rclanmtl.h +++ b/drivers/net/rclanmtl.h @@ -39,12 +39,12 @@ /* Linux specific includes */ #include <asm/types.h> -#ifdef RC_LINUX_MODULE /* linux modules need non-library version of string functions */ +#ifdef RC_LINUX_MODULE /* linux modules need non-library version of string functions */ #include <linux/string.h> #else #include <string.h> #endif -#include <linux/delay.h> /* for udelay() */ +#include <linux/delay.h> /* for udelay() */ #include <linux/netdevice.h> #include <linux/if_ether.h> @@ -62,152 +62,141 @@ #define dprintk(args...) { } #endif - /* Typedefs */ /* scalar data types */ -typedef __u8 U8; -typedef __u16 U16; -typedef __u32 U32; -typedef __u8* PU8; -typedef __u16* PU16; -typedef __u32* PU32; -typedef unsigned long BF; -typedef int RC_RETURN; +typedef __u8 U8; +typedef __u16 U16; +typedef __u32 U32; +typedef __u8 *PU8; +typedef __u16 *PU16; +typedef __u32 *PU32; +typedef unsigned long BF; +typedef int RC_RETURN; /* - ** type PFNWAITCALLBACK - ** - ** pointer to void function - type used for WaitCallback in some functions - */ -typedef void (*PFNWAITCALLBACK)(void); /* void argument avoids compiler complaint */ + ** type PFNWAITCALLBACK + ** + ** pointer to void function - type used for WaitCallback in some functions + */ +typedef void (*PFNWAITCALLBACK) (void); /* void argument avoids compiler complaint */ /* - ** type PFNTXCALLBACK - ** - ** Pointer to user's transmit callback function. This user function is - ** called from RCProcI2OMsgQ() when packet have been transmitted from buffers - ** given in the RCI2OSendPacket() function. BufferContext is a pointer to - ** an array of 32 bit context values. These are the values the user assigned - ** and passed in the TCB to the RCI2OSendPacket() function. PcktCount - ** indicates the number of buffer context values in the BufferContext[] array. - ** The User's TransmitCallbackFunction should recover (put back in free queue) - ** the packet buffers associated with the buffer context values. - */ -typedef void (*PFNTXCALLBACK)(U32 Status, - U16 PcktCount, - PU32 BufferContext, - struct net_device *); + ** type PFNTXCALLBACK + ** + ** Pointer to user's transmit callback function. This user function is + ** called from RCProcI2OMsgQ() when packet have been transmitted from buffers + ** given in the RCI2OSendPacket() function. BufferContext is a pointer to + ** an array of 32 bit context values. These are the values the user assigned + ** and passed in the TCB to the RCI2OSendPacket() function. PcktCount + ** indicates the number of buffer context values in the BufferContext[] array. + ** The User's TransmitCallbackFunction should recover (put back in free queue) + ** the packet buffers associated with the buffer context values. + */ +typedef void (*PFNTXCALLBACK) (U32 Status, + U16 PcktCount, + PU32 BufferContext, struct net_device *); /* - ** type PFNRXCALLBACK - ** - ** Pointer to user's receive callback function. This user function - ** is called from RCProcI2OMsgQ() when packets have been received into - ** previously posted packet buffers throught the RCPostRecvBuffers() function. - ** The received callback function should process the Packet Descriptor Block - ** pointed to by PacketDescBlock. See Packet Decription Block below. - */ -typedef void (*PFNRXCALLBACK)(U32 Status, - U8 PktCount, - U32 BucketsRemain, - PU32 PacketDescBlock, - struct net_device *); + ** type PFNRXCALLBACK + ** + ** Pointer to user's receive callback function. This user function + ** is called from RCProcI2OMsgQ() when packets have been received into + ** previously posted packet buffers throught the RCPostRecvBuffers() function. + ** The received callback function should process the Packet Descriptor Block + ** pointed to by PacketDescBlock. See Packet Decription Block below. + */ +typedef void (*PFNRXCALLBACK) (U32 Status, + U8 PktCount, + U32 BucketsRemain, + PU32 PacketDescBlock, struct net_device *); /* - ** type PFNCALLBACK - ** - ** Pointer to user's generic callback function. This user function - ** can be passed to LANReset or LANShutdown and is called when the - ** the reset or shutdown is complete. - ** Param1 and Param2 are invalid for LANReset and LANShutdown. - */ -typedef void (*PFNCALLBACK)(U32 Status, - U32 Param1, - U32 Param2, - struct net_device *dev); + ** type PFNCALLBACK + ** + ** Pointer to user's generic callback function. This user function + ** can be passed to LANReset or LANShutdown and is called when the + ** the reset or shutdown is complete. + ** Param1 and Param2 are invalid for LANReset and LANShutdown. + */ +typedef void (*PFNCALLBACK) (U32 Status, + U32 Param1, U32 Param2, struct net_device * dev); /* ** Message Unit CSR definitions for RedCreek PCI45 board */ -typedef struct tag_rcatu -{ - volatile unsigned long APICRegSel; /* APIC Register Select */ - volatile unsigned long reserved0; - volatile unsigned long APICWinReg; /* APIC Window Register */ - volatile unsigned long reserved1; - volatile unsigned long InMsgReg0; /* inbound message register 0 */ - volatile unsigned long InMsgReg1; /* inbound message register 1 */ - volatile unsigned long OutMsgReg0; /* outbound message register 0 */ - volatile unsigned long OutMsgReg1; /* outbound message register 1 */ - volatile unsigned long InDoorReg; /* inbound doorbell register */ - volatile unsigned long InIntStat; /* inbound interrupt status register */ - volatile unsigned long InIntMask; /* inbound interrupt mask register */ - volatile unsigned long OutDoorReg; /* outbound doorbell register */ - volatile unsigned long OutIntStat; /* outbound interrupt status register */ - volatile unsigned long OutIntMask; /* outbound interrupt mask register */ - volatile unsigned long reserved2; - volatile unsigned long reserved3; - volatile unsigned long InQueue; /* inbound queue port */ - volatile unsigned long OutQueue; /* outbound queue port */ - volatile unsigned long reserved4; - volatile unsigned long reserver5; - /* RedCreek extension */ - volatile unsigned long EtherMacLow; - volatile unsigned long EtherMacHi; - volatile unsigned long IPaddr; - volatile unsigned long IPmask; +typedef struct tag_rcatu { + volatile unsigned long APICRegSel; /* APIC Register Select */ + volatile unsigned long reserved0; + volatile unsigned long APICWinReg; /* APIC Window Register */ + volatile unsigned long reserved1; + volatile unsigned long InMsgReg0; /* inbound message register 0 */ + volatile unsigned long InMsgReg1; /* inbound message register 1 */ + volatile unsigned long OutMsgReg0; /* outbound message register 0 */ + volatile unsigned long OutMsgReg1; /* outbound message register 1 */ + volatile unsigned long InDoorReg; /* inbound doorbell register */ + volatile unsigned long InIntStat; /* inbound interrupt status register */ + volatile unsigned long InIntMask; /* inbound interrupt mask register */ + volatile unsigned long OutDoorReg; /* outbound doorbell register */ + volatile unsigned long OutIntStat; /* outbound interrupt status register */ + volatile unsigned long OutIntMask; /* outbound interrupt mask register */ + volatile unsigned long reserved2; + volatile unsigned long reserved3; + volatile unsigned long InQueue; /* inbound queue port */ + volatile unsigned long OutQueue; /* outbound queue port */ + volatile unsigned long reserved4; + volatile unsigned long reserver5; + /* RedCreek extension */ + volatile unsigned long EtherMacLow; + volatile unsigned long EtherMacHi; + volatile unsigned long IPaddr; + volatile unsigned long IPmask; } *PATU; /* - ** typedef PAB - ** - ** PCI Adapter Block - holds instance specific information. - */ -typedef struct -{ - PATU p_atu; /* ptr to ATU register block */ - PU8 pPci45LinBaseAddr; - PU8 pLinOutMsgBlock; - U32 outMsgBlockPhyAddr; - PFNTXCALLBACK pTransCallbackFunc; - PFNRXCALLBACK pRecvCallbackFunc; - PFNCALLBACK pRebootCallbackFunc; - PFNCALLBACK pCallbackFunc; - U16 IOPState; - U16 InboundMFrameSize; + ** typedef PAB + ** + ** PCI Adapter Block - holds instance specific information. + */ +typedef struct { + PATU p_atu; /* ptr to ATU register block */ + PU8 pPci45LinBaseAddr; + PU8 pLinOutMsgBlock; + U32 outMsgBlockPhyAddr; + PFNTXCALLBACK pTransCallbackFunc; + PFNRXCALLBACK pRecvCallbackFunc; + PFNCALLBACK pRebootCallbackFunc; + PFNCALLBACK pCallbackFunc; + U16 IOPState; + U16 InboundMFrameSize; } *PPAB; /* * Driver Private Area, DPA. */ -typedef struct -{ - U8 id; /* the AdapterID */ - - /* These two field are basically for the RCioctl function. - * I could not determine if they could be avoided. (RAA)*/ - U32 pci_addr; /* the pci address of the adapter */ - U32 pci_addr_len; - - struct timer_list timer; /* timer */ - struct net_device_stats stats; /* the statistics structure */ - unsigned long numOutRcvBuffers;/* number of outstanding receive buffers*/ - unsigned char shutdown; - unsigned char reboot; - unsigned char nexus; - PU8 msgbuf; /* Pointer to Lan Api Private Area */ - PU8 PLanApiPA; /* Pointer to Lan Api Private Area (aligned) */ - PPAB pPab; /* Pointer to the PCI Adapter Block */ +typedef struct { + U8 id; /* the AdapterID */ + + /* These two field are basically for the RCioctl function. + * I could not determine if they could be avoided. (RAA)*/ + U32 pci_addr; /* the pci address of the adapter */ + U32 pci_addr_len; + + struct timer_list timer; /* timer */ + struct net_device_stats stats; /* the statistics structure */ + unsigned long numOutRcvBuffers; /* number of outstanding receive buffers */ + unsigned char shutdown; + unsigned char reboot; + unsigned char nexus; + PU8 msgbuf; /* Pointer to Lan Api Private Area */ + PU8 PLanApiPA; /* Pointer to Lan Api Private Area (aligned) */ + PPAB pPab; /* Pointer to the PCI Adapter Block */ } *PDPA; - - /* PCI/45 Configuration space values */ #define RC_PCI45_VENDOR_ID 0x4916 #define RC_PCI45_DEVICE_ID 0x1960 - /* RedCreek API function return values */ #define RC_RTN_NO_ERROR 0 #define RC_RTN_I2O_NOT_INIT 1 @@ -244,7 +233,6 @@ typedef struct #define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02 #define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0A - /* DetailedStatusCode defines */ #define I2O_LAN_DSC_SUCCESS 0x0000 #define I2O_LAN_DSC_DEVICE_FAILURE 0x0001 @@ -264,7 +252,6 @@ typedef struct #define I2O_LAN_DSC_DESTINATION_ADDRESS_OMITTED 0x000F #define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED 0x0010 - /* ** Packet Description Block (Received packets) ** @@ -301,8 +288,6 @@ typedef struct ** */ - - /* ** Transaction Control Block (TCB) structure ** @@ -368,13 +353,11 @@ typedef struct */ /* Buffer Segment Descriptor */ -typedef struct -{ - U32 size; - U32 phyAddress; -} - BSD, *PBSD; - +typedef struct { + U32 size; + U32 phyAddress; +} BSD, *PBSD; + typedef PU32 PRCTCB; /* ** ------------------------------------------------------------------------- @@ -382,41 +365,40 @@ typedef PU32 PRCTCB; ** ------------------------------------------------------------------------- */ - /* - ** InitRCI2OMsgLayer() - ** - ** Called once prior to using the I2O LAN message transport layer. User - ** provides both the physical and virual address of a locked page buffer - ** that is used as a private buffer for the RedCreek I2O message - ** transport layer. This buffer must be a contigous memory block of a - ** minimum of 16K bytes and long word aligned. The user also must provide - ** the base address of the RedCreek PCI adapter assigned by BIOS or operating - ** system. - ** - ** Inputs: dev - the net_device struct for the device. - ** TransmitCallbackFunction - address of user's TX callback function - ** ReceiveCallbackFunction - address of user's RX callback function - ** RebootCallbackFunction - address of user's reboot callback function - ** - */ -RC_RETURN RCInitI2OMsgLayer(struct net_device *dev, - PFNTXCALLBACK TransmitCallbackFunction, - PFNRXCALLBACK ReceiveCallbackFunction, - PFNCALLBACK RebootCallbackFunction); + ** InitRCI2OMsgLayer() + ** + ** Called once prior to using the I2O LAN message transport layer. User + ** provides both the physical and virual address of a locked page buffer + ** that is used as a private buffer for the RedCreek I2O message + ** transport layer. This buffer must be a contigous memory block of a + ** minimum of 16K bytes and long word aligned. The user also must provide + ** the base address of the RedCreek PCI adapter assigned by BIOS or operating + ** system. + ** + ** Inputs: dev - the net_device struct for the device. + ** TransmitCallbackFunction - address of user's TX callback function + ** ReceiveCallbackFunction - address of user's RX callback function + ** RebootCallbackFunction - address of user's reboot callback function + ** + */ +RC_RETURN RCInitI2OMsgLayer (struct net_device *dev, + PFNTXCALLBACK TransmitCallbackFunction, + PFNRXCALLBACK ReceiveCallbackFunction, + PFNCALLBACK RebootCallbackFunction); /* - ** RCSetRavlinIPandMask() - ** - ** Set the Ravlin 45/PCI cards IP address and network mask. - ** - ** IP address and mask must be in network byte order. - ** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be - ** 0x04030201 and 0x00FFFFFF on a little endian machine. - ** - */ -RC_RETURN RCSetRavlinIPandMask(struct net_device *dev, U32 ipAddr, U32 netMask); - + ** RCSetRavlinIPandMask() + ** + ** Set the Ravlin 45/PCI cards IP address and network mask. + ** + ** IP address and mask must be in network byte order. + ** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be + ** 0x04030201 and 0x00FFFFFF on a little endian machine. + ** + */ +RC_RETURN RCSetRavlinIPandMask (struct net_device *dev, U32 ipAddr, + U32 netMask); /* ** ========================================================================= @@ -427,136 +409,130 @@ RC_RETURN RCSetRavlinIPandMask(struct net_device *dev, U32 ipAddr, U32 netMask); ** ========================================================================= */ RC_RETURN -RCGetRavlinIPandMask(struct net_device *dev, PU32 pIpAddr, PU32 pNetMask, - PFNWAITCALLBACK WaitCallback); +RCGetRavlinIPandMask (struct net_device *dev, PU32 pIpAddr, PU32 pNetMask, + PFNWAITCALLBACK WaitCallback); /* - ** RCProcI2OMsgQ() - ** - ** Called from user's polling loop or Interrupt Service Routine for a PCI - ** interrupt from the RedCreek PCI adapter. User responsible for determining - ** and hooking the PCI interrupt. This function will call the registered - ** callback functions, TransmitCallbackFunction or ReceiveCallbackFunction, - ** if a TX or RX transaction has completed. - */ -void RCProcI2OMsgQ(struct net_device *dev); - + ** RCProcI2OMsgQ() + ** + ** Called from user's polling loop or Interrupt Service Routine for a PCI + ** interrupt from the RedCreek PCI adapter. User responsible for determining + ** and hooking the PCI interrupt. This function will call the registered + ** callback functions, TransmitCallbackFunction or ReceiveCallbackFunction, + ** if a TX or RX transaction has completed. + */ +void RCProcI2OMsgQ (struct net_device *dev); /* - ** Disable and Enable I2O interrupts. I2O interrupts are enabled at Init time - ** but can be disabled and re-enabled through these two function calls. - ** Packets will still be put into any posted received buffers and packets will - ** be sent through RCI2OSendPacket() functions. Disabling I2O interrupts - ** will prevent hardware interrupt to host even though the outbound I2O msg - ** queue is not emtpy. - */ -RC_RETURN RCEnableI2OInterrupts(struct net_device *dev); -RC_RETURN RCDisableI2OInterrupts(struct net_device *dev); - + ** Disable and Enable I2O interrupts. I2O interrupts are enabled at Init time + ** but can be disabled and re-enabled through these two function calls. + ** Packets will still be put into any posted received buffers and packets will + ** be sent through RCI2OSendPacket() functions. Disabling I2O interrupts + ** will prevent hardware interrupt to host even though the outbound I2O msg + ** queue is not emtpy. + */ +RC_RETURN RCEnableI2OInterrupts (struct net_device *dev); +RC_RETURN RCDisableI2OInterrupts (struct net_device *dev); /* - ** RCPostRecvBuffers() - ** - ** Post user's page locked buffers for use by the PCI adapter to - ** return ethernet packets received from the LAN. Transaction Control Block, - ** provided by user, contains buffer descriptor(s) which includes a buffer - ** context number along with buffer size and physical address. See TCB above. - ** The buffer context and actual packet length are returned to the - ** ReceiveCallbackFunction when packets have been received. Buffers posted - ** to the RedCreek adapter are considered owned by the adapter until the - ** context is return to user through the ReceiveCallbackFunction. - */ -RC_RETURN RCPostRecvBuffers(struct net_device *dev, PRCTCB pTransactionCtrlBlock); + ** RCPostRecvBuffers() + ** + ** Post user's page locked buffers for use by the PCI adapter to + ** return ethernet packets received from the LAN. Transaction Control Block, + ** provided by user, contains buffer descriptor(s) which includes a buffer + ** context number along with buffer size and physical address. See TCB above. + ** The buffer context and actual packet length are returned to the + ** ReceiveCallbackFunction when packets have been received. Buffers posted + ** to the RedCreek adapter are considered owned by the adapter until the + ** context is return to user through the ReceiveCallbackFunction. + */ +RC_RETURN RCPostRecvBuffers (struct net_device *dev, + PRCTCB pTransactionCtrlBlock); #define MAX_NMBR_POST_BUFFERS_PER_MSG 32 /* - ** RCI2OSendPacket() - ** - ** Send user's ethernet packet from a locked page buffer. - ** Packet must have full MAC header, however without a CRC. - ** Initiator context is a user provided value that is returned - ** to the TransmitCallbackFunction when packet buffer is free. - ** Transmit buffer are considered owned by the adapter until context's - ** returned to user through the TransmitCallbackFunction. - */ -RC_RETURN RCI2OSendPacket(struct net_device *dev, - U32 context, - PRCTCB pTransactionCtrlBlock); - + ** RCI2OSendPacket() + ** + ** Send user's ethernet packet from a locked page buffer. + ** Packet must have full MAC header, however without a CRC. + ** Initiator context is a user provided value that is returned + ** to the TransmitCallbackFunction when packet buffer is free. + ** Transmit buffer are considered owned by the adapter until context's + ** returned to user through the TransmitCallbackFunction. + */ +RC_RETURN RCI2OSendPacket (struct net_device *dev, + U32 context, PRCTCB pTransactionCtrlBlock); /* Ethernet Link Statistics structure */ -typedef struct tag_RC_link_stats -{ - U32 TX_good; /* good transmit frames */ - U32 TX_maxcol; /* frames not TX due to MAX collisions */ - U32 TX_latecol; /* frames not TX due to late collisions */ - U32 TX_urun; /* frames not TX due to DMA underrun */ - U32 TX_crs; /* frames TX with lost carrier sense */ - U32 TX_def; /* frames deferred due to activity on link */ - U32 TX_singlecol; /* frames TX with one and only on collision */ - U32 TX_multcol; /* frames TX with more than one collision */ - U32 TX_totcol; /* total collisions detected during TX */ - U32 Rcv_good; /* good frames received */ - U32 Rcv_CRCerr; /* frames RX and discarded with CRC errors */ - U32 Rcv_alignerr; /* frames RX with alignment and CRC errors */ - U32 Rcv_reserr; /* good frames discarded due to no RX buffer */ - U32 Rcv_orun; /* RX frames lost due to FIFO overrun */ - U32 Rcv_cdt; /* RX frames with collision during RX */ - U32 Rcv_runt; /* RX frames shorter than 64 bytes */ -} - RCLINKSTATS, *P_RCLINKSTATS; +typedef struct tag_RC_link_stats { + U32 TX_good; /* good transmit frames */ + U32 TX_maxcol; /* frames not TX due to MAX collisions */ + U32 TX_latecol; /* frames not TX due to late collisions */ + U32 TX_urun; /* frames not TX due to DMA underrun */ + U32 TX_crs; /* frames TX with lost carrier sense */ + U32 TX_def; /* frames deferred due to activity on link */ + U32 TX_singlecol; /* frames TX with one and only on collision */ + U32 TX_multcol; /* frames TX with more than one collision */ + U32 TX_totcol; /* total collisions detected during TX */ + U32 Rcv_good; /* good frames received */ + U32 Rcv_CRCerr; /* frames RX and discarded with CRC errors */ + U32 Rcv_alignerr; /* frames RX with alignment and CRC errors */ + U32 Rcv_reserr; /* good frames discarded due to no RX buffer */ + U32 Rcv_orun; /* RX frames lost due to FIFO overrun */ + U32 Rcv_cdt; /* RX frames with collision during RX */ + U32 Rcv_runt; /* RX frames shorter than 64 bytes */ +} RCLINKSTATS, *P_RCLINKSTATS; /* - ** RCGetLinkStatistics() - ** - ** Returns link statistics in user's structure at address StatsReturnAddr - ** If given, not NULL, the function WaitCallback is called during the wait - ** loop while waiting for the adapter to respond. - */ -RC_RETURN RCGetLinkStatistics(struct net_device *dev, - P_RCLINKSTATS StatsReturnAddr, - PFNWAITCALLBACK WaitCallback); + ** RCGetLinkStatistics() + ** + ** Returns link statistics in user's structure at address StatsReturnAddr + ** If given, not NULL, the function WaitCallback is called during the wait + ** loop while waiting for the adapter to respond. + */ +RC_RETURN RCGetLinkStatistics (struct net_device *dev, + P_RCLINKSTATS StatsReturnAddr, + PFNWAITCALLBACK WaitCallback); /* - ** RCGetLinkStatus() - ** - ** Return link status, up or down, to user's location addressed by ReturnAddr. - ** If given, not NULL, the function WaitCallback is called during the wait - ** loop while waiting for the adapter to respond. - */ -RC_RETURN RCGetLinkStatus(struct net_device *dev, - PU32 pReturnStatus, - PFNWAITCALLBACK WaitCallback); - + ** RCGetLinkStatus() + ** + ** Return link status, up or down, to user's location addressed by ReturnAddr. + ** If given, not NULL, the function WaitCallback is called during the wait + ** loop while waiting for the adapter to respond. + */ +RC_RETURN RCGetLinkStatus (struct net_device *dev, + PU32 pReturnStatus, PFNWAITCALLBACK WaitCallback); + /* Link Status defines - value returned in pReturnStatus */ #define RC_LAN_LINK_STATUS_DOWN 0 #define RC_LAN_LINK_STATUS_UP 1 /* - ** RCGetMAC() - ** - ** Get the current MAC address assigned to user. RedCreek Ravlin 45/PCI - ** has two MAC addresses. One which is private to the PCI Card, and - ** another MAC which is given to the user as its link layer MAC address. The - ** adapter runs in promiscous mode because of the dual address requirement. - ** The MAC address is returned to the unsigned char array pointer to by mac. - */ -RC_RETURN RCGetMAC(struct net_device *dev, PFNWAITCALLBACK WaitCallback); + ** RCGetMAC() + ** + ** Get the current MAC address assigned to user. RedCreek Ravlin 45/PCI + ** has two MAC addresses. One which is private to the PCI Card, and + ** another MAC which is given to the user as its link layer MAC address. The + ** adapter runs in promiscous mode because of the dual address requirement. + ** The MAC address is returned to the unsigned char array pointer to by mac. + */ +RC_RETURN RCGetMAC (struct net_device *dev, PFNWAITCALLBACK WaitCallback); /* - ** RCSetMAC() - ** - ** Set a new user port MAC address. This address will be returned on - ** subsequent RCGetMAC() calls. - */ -RC_RETURN RCSetMAC(struct net_device *dev, PU8 mac); + ** RCSetMAC() + ** + ** Set a new user port MAC address. This address will be returned on + ** subsequent RCGetMAC() calls. + */ +RC_RETURN RCSetMAC (struct net_device *dev, PU8 mac); /* - ** RCSetLinkSpeed() - ** - ** set adapter's link speed based on given input code. - */ -RC_RETURN RCSetLinkSpeed(struct net_device *dev, U16 LinkSpeedCode); + ** RCSetLinkSpeed() + ** + ** set adapter's link speed based on given input code. + */ +RC_RETURN RCSetLinkSpeed (struct net_device *dev, U16 LinkSpeedCode); /* Set link speed codes */ #define LNK_SPD_AUTO_NEG_NWAY 0 #define LNK_SPD_100MB_FULL 1 @@ -564,14 +540,11 @@ RC_RETURN RCSetLinkSpeed(struct net_device *dev, U16 LinkSpeedCode); #define LNK_SPD_10MB_FULL 3 #define LNK_SPD_10MB_HALF 4 - - - /* - ** RCGetLinkSpeed() - ** - ** Return link speed code. - */ + ** RCGetLinkSpeed() + ** + ** Return link speed code. + */ /* Return link speed codes */ #define LNK_SPD_UNKNOWN 0 #define LNK_SPD_100MB_FULL 1 @@ -580,7 +553,8 @@ RC_RETURN RCSetLinkSpeed(struct net_device *dev, U16 LinkSpeedCode); #define LNK_SPD_10MB_HALF 4 RC_RETURN -RCGetLinkSpeed(struct net_device *dev, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback); +RCGetLinkSpeed (struct net_device *dev, PU32 pLinkSpeedCode, + PFNWAITCALLBACK WaitCallback); /* ** ========================================================================= ** RCSetPromiscuousMode(struct net_device *dev, U16 Mode) @@ -593,8 +567,7 @@ RCGetLinkSpeed(struct net_device *dev, PU32 pLinkSpeedCode, PFNWAITCALLBACK Wait */ #define PROMISCUOUS_MODE_OFF 0 #define PROMISCUOUS_MODE_ON 1 -RC_RETURN -RCSetPromiscuousMode(struct net_device *dev, U16 Mode); +RC_RETURN RCSetPromiscuousMode (struct net_device *dev, U16 Mode); /* ** ========================================================================= ** RCGetPromiscuousMode(struct net_device *dev, PU32 pMode, PFNWAITCALLBACK WaitCallback) @@ -608,7 +581,8 @@ RCSetPromiscuousMode(struct net_device *dev, U16 Mode); ** ========================================================================= */ RC_RETURN -RCGetPromiscuousMode(struct net_device *dev, PU32 pMode, PFNWAITCALLBACK WaitCallback); +RCGetPromiscuousMode (struct net_device *dev, PU32 pMode, + PFNWAITCALLBACK WaitCallback); /* ** ========================================================================= @@ -622,8 +596,7 @@ RCGetPromiscuousMode(struct net_device *dev, PU32 pMode, PFNWAITCALLBACK WaitCal */ #define BROADCAST_MODE_OFF 0 #define BROADCAST_MODE_ON 1 -RC_RETURN -RCSetBroadcastMode(struct net_device *dev, U16 Mode); +RC_RETURN RCSetBroadcastMode (struct net_device *dev, U16 Mode); /* ** ========================================================================= ** RCGetBroadcastMode(struct net_device *dev, PU32 pMode, PFNWAITCALLBACK WaitCallback) @@ -637,7 +610,8 @@ RCSetBroadcastMode(struct net_device *dev, U16 Mode); ** ========================================================================= */ RC_RETURN -RCGetBroadcastMode(struct net_device *dev, PU32 pMode, PFNWAITCALLBACK WaitCallback); +RCGetBroadcastMode (struct net_device *dev, PU32 pMode, + PFNWAITCALLBACK WaitCallback); /* ** ========================================================================= ** RCReportDriverCapability(struct net_device *dev, U32 capability) @@ -647,8 +621,7 @@ RCGetBroadcastMode(struct net_device *dev, PU32 pMode, PFNWAITCALLBACK WaitCallb ** ** ========================================================================= */ -RC_RETURN -RCReportDriverCapability(struct net_device *dev, U32 capability); +RC_RETURN RCReportDriverCapability (struct net_device *dev, U32 capability); /* ** RCGetFirmwareVer() @@ -658,7 +631,8 @@ RCReportDriverCapability(struct net_device *dev, U32 capability); ** WARNING: user's space pointed to by pFirmString should be at least 60 bytes. */ RC_RETURN -RCGetFirmwareVer(struct net_device *dev, PU8 pFirmString, PFNWAITCALLBACK WaitCallback); +RCGetFirmwareVer (struct net_device *dev, PU8 pFirmString, + PFNWAITCALLBACK WaitCallback); /* ** ---------------------------------------------- @@ -666,61 +640,61 @@ RCGetFirmwareVer(struct net_device *dev, PU8 pFirmString, PFNWAITCALLBACK WaitCa ** ---------------------------------------------- */ /* resource flag bit assignments for RCResetLANCard() & RCShutdownLANCard() */ -#define RC_RESOURCE_RETURN_POSTED_RX_BUCKETS 0x0001 +#define RC_RESOURCE_RETURN_POSTED_RX_BUCKETS 0x0001 #define RC_RESOURCE_RETURN_PEND_TX_BUFFERS 0x0002 /* - ** RCResetLANCard() - ** - ** Reset LAN card operation. Causes a software reset of the ethernet - ** controller and restarts the command and receive units. Depending on - ** the ResourceFlags given, the buffers are either returned to the - ** host with reply status of I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER and - ** detailed status of I2O_LAN_DSC_CANCELED (new receive buffers must be - ** posted after issuing this) OR the buffers are kept and reused by - ** the ethernet controller. If CallbackFunction is not NULL, the function - ** will be called when the reset is complete. If the CallbackFunction is - ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset - ** to complete (please disable I2O interrupts during this method). - ** Any outstanding transmit or receive buffers that are complete will be - ** returned via the normal reply messages before the requested resource - ** buffers are returned. - ** A call to RCPostRecvBuffers() is needed to return the ethernet to full - ** operation if the receive buffers were returned during LANReset. - ** Note: The IOP status is not affected by a LAN reset. - */ -RC_RETURN RCResetLANCard(struct net_device *dev, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction); - + ** RCResetLANCard() + ** + ** Reset LAN card operation. Causes a software reset of the ethernet + ** controller and restarts the command and receive units. Depending on + ** the ResourceFlags given, the buffers are either returned to the + ** host with reply status of I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER and + ** detailed status of I2O_LAN_DSC_CANCELED (new receive buffers must be + ** posted after issuing this) OR the buffers are kept and reused by + ** the ethernet controller. If CallbackFunction is not NULL, the function + ** will be called when the reset is complete. If the CallbackFunction is + ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset + ** to complete (please disable I2O interrupts during this method). + ** Any outstanding transmit or receive buffers that are complete will be + ** returned via the normal reply messages before the requested resource + ** buffers are returned. + ** A call to RCPostRecvBuffers() is needed to return the ethernet to full + ** operation if the receive buffers were returned during LANReset. + ** Note: The IOP status is not affected by a LAN reset. + */ +RC_RETURN RCResetLANCard (struct net_device *dev, U16 ResourceFlags, + PU32 ReturnAddr, PFNCALLBACK CallbackFunction); /* - ** RCShutdownLANCard() - ** - ** Shutdown LAN card operation and put into an idle (suspended) state. - ** The LAN card is restarted with RCResetLANCard() function. - ** Depending on the ResourceFlags given, the buffers are either returned - ** to the host with reply status of I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER - ** and detailed status of I2O_LAN_DSC_CANCELED (new receive buffers must be - ** posted after issuing this) OR the buffers are kept and reused by - ** the ethernet controller. If CallbackFunction is not NULL, the function - ** will be called when the reset is complete. If the CallbackFunction is - ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset - ** to complete (please disable I2O interrupts during this method). - ** Any outstanding transmit or receive buffers that are complete will be - ** returned via the normal reply messages before the requested resource - ** buffers are returned. - ** Note: The IOP status is not affected by a LAN shutdown. - */ -RC_RETURN -RCShutdownLANCard(struct net_device *dev, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction); + ** RCShutdownLANCard() + ** + ** Shutdown LAN card operation and put into an idle (suspended) state. + ** The LAN card is restarted with RCResetLANCard() function. + ** Depending on the ResourceFlags given, the buffers are either returned + ** to the host with reply status of I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER + ** and detailed status of I2O_LAN_DSC_CANCELED (new receive buffers must be + ** posted after issuing this) OR the buffers are kept and reused by + ** the ethernet controller. If CallbackFunction is not NULL, the function + ** will be called when the reset is complete. If the CallbackFunction is + ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset + ** to complete (please disable I2O interrupts during this method). + ** Any outstanding transmit or receive buffers that are complete will be + ** returned via the normal reply messages before the requested resource + ** buffers are returned. + ** Note: The IOP status is not affected by a LAN shutdown. + */ +RC_RETURN +RCShutdownLANCard (struct net_device *dev, U16 ResourceFlags, PU32 ReturnAddr, + PFNCALLBACK CallbackFunction); /* - ** RCResetIOP(); - ** Initializes IOPState to I2O_IOP_STATE_RESET. - ** Stops access to outbound message Q. - ** Discards any outstanding transmit or posted receive buffers. - ** Clears outbound message Q. - */ -RC_RETURN -RCResetIOP(struct net_device *dev); - -#endif /* RCLANMTL_H */ + ** RCResetIOP(); + ** Initializes IOPState to I2O_IOP_STATE_RESET. + ** Stops access to outbound message Q. + ** Discards any outstanding transmit or posted receive buffers. + ** Clears outbound message Q. + */ +RC_RETURN RCResetIOP (struct net_device *dev); + +#endif /* RCLANMTL_H */ diff --git a/drivers/net/rcpci45.c b/drivers/net/rcpci45.c index 52f65723b344..3768ed0548d5 100644 --- a/drivers/net/rcpci45.c +++ b/drivers/net/rcpci45.c @@ -57,14 +57,12 @@ #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/timer.h> -#include <asm/irq.h> /* For NR_IRQS only. */ +#include <asm/irq.h> /* For NR_IRQS only. */ #include <asm/bitops.h> #include <asm/uaccess.h> - - static char version[] __initdata = -"RedCreek Communications PCI linux driver version 2.03\n"; + "RedCreek Communications PCI linux driver version 2.03\n"; #define RC_LINUX_MODULE #include "rclanmtl.h" @@ -78,339 +76,349 @@ static char version[] __initdata = #define RC_PCI45_VENDOR_ID 0x4916 #define RC_PCI45_DEVICE_ID 0x1960 -#define MAX_ETHER_SIZE 1520 +#define MAX_ETHER_SIZE 1520 #define MAX_NMBR_RCV_BUFFERS 96 #define RC_POSTED_BUFFERS_LOW_MARK MAX_NMBR_RCV_BUFFERS-16 -#define BD_SIZE 3 /* Bucket Descriptor size */ -#define BD_LEN_OFFSET 2 /* Bucket Descriptor offset to length field */ - +#define BD_SIZE 3 /* Bucket Descriptor size */ +#define BD_LEN_OFFSET 2 /* Bucket Descriptor offset to length field */ /* RedCreek LAN device Target ID */ -#define RC_LAN_TARGET_ID 0x10 +#define RC_LAN_TARGET_ID 0x10 /* RedCreek's OSM default LAN receive Initiator */ -#define DEFAULT_RECV_INIT_CONTEXT 0xA17 - +#define DEFAULT_RECV_INIT_CONTEXT 0xA17 static U32 DriverControlWord; -static void rc_timer(unsigned long); - -static int RCinit(struct net_device *); +static void rc_timer (unsigned long); -static int RCopen(struct net_device *); -static int RC_xmit_packet(struct sk_buff *, struct net_device *); -static void RCinterrupt(int, void *, struct pt_regs *); -static int RCclose(struct net_device *dev); -static struct net_device_stats *RCget_stats(struct net_device *); -static int RCioctl(struct net_device *, struct ifreq *, int); -static int RCconfig(struct net_device *, struct ifmap *); -static void RCxmit_callback(U32, U16, PU32, struct net_device *); -static void RCrecv_callback(U32, U8, U32, PU32, struct net_device *); -static void RCreset_callback(U32, U32, U32, struct net_device *); -static void RCreboot_callback(U32, U32, U32, struct net_device *); -static int RC_allocate_and_post_buffers(struct net_device *, int); +static int RCinit (struct net_device *); +static int RCopen (struct net_device *); +static int RC_xmit_packet (struct sk_buff *, struct net_device *); +static void RCinterrupt (int, void *, struct pt_regs *); +static int RCclose (struct net_device *dev); +static struct net_device_stats *RCget_stats (struct net_device *); +static int RCioctl (struct net_device *, struct ifreq *, int); +static int RCconfig (struct net_device *, struct ifmap *); +static void RCxmit_callback (U32, U16, PU32, struct net_device *); +static void RCrecv_callback (U32, U8, U32, PU32, struct net_device *); +static void RCreset_callback (U32, U32, U32, struct net_device *); +static void RCreboot_callback (U32, U32, U32, struct net_device *); +static int RC_allocate_and_post_buffers (struct net_device *, int); static struct pci_device_id rcpci45_pci_table[] __devinitdata = { - { RC_PCI45_VENDOR_ID, RC_PCI45_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, - { } + {RC_PCI45_VENDOR_ID, RC_PCI45_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + {} }; -MODULE_DEVICE_TABLE(pci, rcpci45_pci_table); +MODULE_DEVICE_TABLE (pci, rcpci45_pci_table); -static void __exit rcpci45_remove_one(struct pci_dev *pdev) +static void __exit +rcpci45_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = pci_get_drvdata (pdev); PDPA pDpa = dev->priv; - if (!dev) { - printk (KERN_ERR "(rcpci45 driver:) remove non-existent device\n"); - return; - } + if (!dev) { + printk (KERN_ERR + "(rcpci45 driver:) remove non-existent device\n"); + return; + } - dprintk("remove_one: IOP reset: 0x%x\n", RCResetIOP(dev)); + dprintk ("remove_one: IOP reset: 0x%x\n", RCResetIOP (dev)); /* RAA Inspired by starfire.c and yellowfin.c we keep these * here. */ - unregister_netdev(dev); - free_irq(dev->irq, dev); - iounmap((void *)dev->base_addr); - pci_release_regions(pdev); - kfree(pDpa->PLanApiPA); - kfree(pDpa->pPab); - kfree(pDpa); - kfree(dev); - pci_set_drvdata(pdev, NULL); + unregister_netdev (dev); + free_irq (dev->irq, dev); + iounmap ((void *) dev->base_addr); + pci_release_regions (pdev); + kfree (pDpa->PLanApiPA); + kfree (pDpa->pPab); + kfree (pDpa); + kfree (dev); + pci_set_drvdata (pdev, NULL); } -static int RCinit(struct net_device *dev) +static int +RCinit (struct net_device *dev) { - dev->open = &RCopen; - dev->hard_start_xmit = &RC_xmit_packet; - dev->stop = &RCclose; - dev->get_stats = &RCget_stats; - dev->do_ioctl = &RCioctl; - dev->set_config = &RCconfig; - return 0; + dev->open = &RCopen; + dev->hard_start_xmit = &RC_xmit_packet; + dev->stop = &RCclose; + dev->get_stats = &RCget_stats; + dev->do_ioctl = &RCioctl; + dev->set_config = &RCconfig; + return 0; } -static int rcpci45_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int +rcpci45_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { - unsigned long *vaddr; - PDPA pDpa; - int error; - static int card_idx = -1; - struct net_device *dev; - unsigned long pci_start, pci_len; - - card_idx++; - - /* - * Allocate and fill new device structure. - * We need enough for struct net_device plus DPA plus the LAN API private - * area, which requires a minimum of 16KB. The top of the allocated - * area will be assigned to struct net_device; the next chunk will be - * assigned to DPA; and finally, the rest will be assigned to the - * the LAN API layer. - */ - - dev = init_etherdev(NULL, sizeof(*pDpa)); - if (!dev) { - printk(KERN_ERR "(rcpci45 driver:) unable to allocate in init_etherdev\n"); - error = -ENOMEM; - goto err_out; - } - - error = pci_enable_device(pdev); - if (error) { - printk(KERN_ERR "(rcpci45 driver:) %d: unable to enable pci device, aborting\n",card_idx); - goto err_out; - } - error = -ENOMEM; - pci_start = pci_resource_start(pdev,0); - pci_len = pci_resource_len(pdev,0); - - pci_set_drvdata(pdev, dev); - - pDpa = dev->priv; - pDpa->id = card_idx; - pDpa->pci_addr = pci_start; - - if (!pci_start || !(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { - printk(KERN_ERR "(rcpci45 driver:) No PCI memory resources! Aborting.\n"); - error = -EBUSY; - goto err_out_free_dev; - } - - /* - * Save the starting address of the LAN API private area. We'll - * pass that to RCInitI2OMsgLayer(). - */ - /* RAA FIXME: This size should be a #define somewhere after I - * clear up some questions: What flags are neeeded in the alloc below - * and what needs to be done before the memarea is long word aligned? - * (Look in old code for an approach.) (Also note that the 16K below - * is substantially less than the 32K allocated before (even though - * some of the spacce was used for data structures.) */ - pDpa->msgbuf = kmalloc(16384, GFP_KERNEL); - if (!pDpa->msgbuf) { - printk(KERN_ERR "(rcpci45 driver:) Could not allocate %d byte memory for the private msgbuf!\n", 16384); /* RAA FIXME not hardcoded! */ - goto err_out_free_dev; - } - pDpa->PLanApiPA = (void *)(((long)pDpa->msgbuf + 0xff) & ~0xff); - - dprintk("pDpa->PLanApiPA = 0x%x\n", (uint)pDpa->PLanApiPA); - - /* The adapter is accessible through memory-access read/write, not - * I/O read/write. Thus, we need to map it to some virtual address - * area in order to access the registers as normal memory. - */ - error = pci_request_regions(pdev, dev->name); - if (error) - goto err_out_free_msgbuf; - - vaddr = (ulong *) ioremap (pci_start, pci_len); - if (!vaddr) { - printk(KERN_ERR "(rcpci45 driver:) Unable to remap address range from %lu to %lu\n", pci_start, pci_start+pci_len); - goto err_out_free_region; - } - - dprintk("rcpci45_init_one: 0x%x, priv = 0x%x, vaddr = 0x%x\n", - (uint)dev, (uint)dev->priv, (uint)vaddr); - dev->base_addr = (unsigned long)vaddr; - dev->irq = pdev->irq; - - dev->init = &RCinit; - - return 0; /* success */ - - err_out_free_region: - pci_release_regions(pdev); - err_out_free_msgbuf: - kfree(pDpa->msgbuf); - err_out_free_dev: - unregister_netdev(dev); - kfree(dev); - err_out: - card_idx--; - return error; + unsigned long *vaddr; + PDPA pDpa; + int error; + static int card_idx = -1; + struct net_device *dev; + unsigned long pci_start, pci_len; + + card_idx++; + + /* + * Allocate and fill new device structure. + * We need enough for struct net_device plus DPA plus the LAN API private + * area, which requires a minimum of 16KB. The top of the allocated + * area will be assigned to struct net_device; the next chunk will be + * assigned to DPA; and finally, the rest will be assigned to the + * the LAN API layer. + */ + + dev = init_etherdev (NULL, sizeof (*pDpa)); + if (!dev) { + printk (KERN_ERR + "(rcpci45 driver:) unable to allocate in init_etherdev\n"); + error = -ENOMEM; + goto err_out; + } + + error = pci_enable_device (pdev); + if (error) { + printk (KERN_ERR + "(rcpci45 driver:) %d: unable to enable pci device, aborting\n", + card_idx); + goto err_out; + } + error = -ENOMEM; + pci_start = pci_resource_start (pdev, 0); + pci_len = pci_resource_len (pdev, 0); + + pci_set_drvdata (pdev, dev); + + pDpa = dev->priv; + pDpa->id = card_idx; + pDpa->pci_addr = pci_start; + + if (!pci_start || !(pci_resource_flags (pdev, 0) & IORESOURCE_MEM)) { + printk (KERN_ERR + "(rcpci45 driver:) No PCI memory resources! Aborting.\n"); + error = -EBUSY; + goto err_out_free_dev; + } + + /* + * Save the starting address of the LAN API private area. We'll + * pass that to RCInitI2OMsgLayer(). + */ + /* RAA FIXME: This size should be a #define somewhere after I + * clear up some questions: What flags are neeeded in the alloc below + * and what needs to be done before the memarea is long word aligned? + * (Look in old code for an approach.) (Also note that the 16K below + * is substantially less than the 32K allocated before (even though + * some of the spacce was used for data structures.) */ + pDpa->msgbuf = kmalloc (16384, GFP_KERNEL); + if (!pDpa->msgbuf) { + printk (KERN_ERR "(rcpci45 driver:) Could not allocate %d byte memory for the private msgbuf!\n", 16384); /* RAA FIXME not hardcoded! */ + goto err_out_free_dev; + } + pDpa->PLanApiPA = (void *) (((long) pDpa->msgbuf + 0xff) & ~0xff); + + dprintk ("pDpa->PLanApiPA = 0x%x\n", (uint) pDpa->PLanApiPA); + + /* The adapter is accessible through memory-access read/write, not + * I/O read/write. Thus, we need to map it to some virtual address + * area in order to access the registers as normal memory. + */ + error = pci_request_regions (pdev, dev->name); + if (error) + goto err_out_free_msgbuf; + + vaddr = (ulong *) ioremap (pci_start, pci_len); + if (!vaddr) { + printk (KERN_ERR + "(rcpci45 driver:) Unable to remap address range from %lu to %lu\n", + pci_start, pci_start + pci_len); + goto err_out_free_region; + } + + dprintk ("rcpci45_init_one: 0x%x, priv = 0x%x, vaddr = 0x%x\n", + (uint) dev, (uint) dev->priv, (uint) vaddr); + dev->base_addr = (unsigned long) vaddr; + dev->irq = pdev->irq; + + dev->init = &RCinit; + + return 0; /* success */ + +err_out_free_region: + pci_release_regions (pdev); +err_out_free_msgbuf: + kfree (pDpa->msgbuf); +err_out_free_dev: + unregister_netdev (dev); + kfree (dev); +err_out: + card_idx--; + return error; } static struct pci_driver rcpci45_driver = { - name: "rcpci45", - id_table: rcpci45_pci_table, - probe: rcpci45_init_one, - remove: rcpci45_remove_one, + name: "rcpci45", + id_table: rcpci45_pci_table, + probe: rcpci45_init_one, + remove: rcpci45_remove_one, }; -static int __init rcpci_init_module(void) +static int __init +rcpci_init_module (void) { - int rc = pci_module_init(&rcpci45_driver); + int rc = pci_module_init (&rcpci45_driver); if (!rc) - printk(KERN_INFO "%s",version); + printk (KERN_INFO "%s", version); return rc; } static int -RCopen(struct net_device *dev) +RCopen (struct net_device *dev) { - int post_buffers = MAX_NMBR_RCV_BUFFERS; - PDPA pDpa = dev->priv; - int count = 0; - int requested = 0; - int error; - - dprintk("(rcpci45 driver:) RCopen\n"); - - /* Request a shared interrupt line. */ - error=request_irq(dev->irq, RCinterrupt, SA_SHIRQ, dev->name, dev); - if (error) { - printk(KERN_ERR "(rcpci45 driver:) %s: unable to get IRQ %d\n", dev->name, dev->irq ); - goto err_out; - } - - error = RCInitI2OMsgLayer(dev, (PFNTXCALLBACK)RCxmit_callback, - (PFNRXCALLBACK)RCrecv_callback, - (PFNCALLBACK)RCreboot_callback); - if (error) { - printk(KERN_ERR "(rcpci45 driver:) Unable to initialize msg layer\n"); - goto err_out_free_irq; - } - if ( (error=RCGetMAC(dev, NULL)) ) { - printk(KERN_ERR "(rcpci45 driver:) Unable to get adapter MAC\n"); - goto err_out_free_irq; - } - - DriverControlWord |= WARM_REBOOT_CAPABLE; - RCReportDriverCapability(dev, DriverControlWord); - - printk(KERN_INFO "%s: RedCreek Communications IPSEC VPN adapter\n", - dev->name); - - - /* RAA: Old RCopen starts here */ - RCEnableI2OInterrupts(dev); - - /* RAA Hmm, how does the comment below jibe with the newly imported - * code above? A FIXME!!*/ - if (pDpa->nexus) { - /* This is not the first time RCopen is called. Thus, - * the interface was previously opened and later closed - * by RCclose(). RCclose() does a Shutdown; to wake up - * the adapter, a reset is mandatory before we can post - * receive buffers. However, if the adapter initiated - * a reboot while the interface was closed -- and interrupts - * were turned off -- we need will need to reinitialize - * the adapter, rather than simply waking it up. - */ - dprintk(KERN_INFO "Waking up adapter...\n"); - RCResetLANCard(dev,0,0,0); - } else - pDpa->nexus = 1; - - while(post_buffers) { - if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG) - requested = MAX_NMBR_POST_BUFFERS_PER_MSG; - else - requested = post_buffers; - count = RC_allocate_and_post_buffers(dev, requested); - - if ( count < requested ) - { - /* - * Check to see if we were able to post any buffers at all. - */ - if (post_buffers == MAX_NMBR_RCV_BUFFERS) { - printk(KERN_ERR "(rcpci45 driver:) Error RCopen: not able to allocate any buffers\r\n"); - return(-ENOMEM); - } - printk(KERN_WARNING "(rcpci45 driver:) Warning RCopen: not able to allocate all requested buffers\r\n"); - break; /* we'll try to post more buffers later */ - } else - post_buffers -= count; - } - pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers; - pDpa->shutdown = 0; /* just in case */ - dprintk("RCopen: posted %d buffers\n", (uint)pDpa->numOutRcvBuffers); - MOD_INC_USE_COUNT; - netif_start_queue(dev); - return 0; - - err_out_free_irq: - free_irq(dev->irq, dev); - err_out: - return error; + int post_buffers = MAX_NMBR_RCV_BUFFERS; + PDPA pDpa = dev->priv; + int count = 0; + int requested = 0; + int error; + + dprintk ("(rcpci45 driver:) RCopen\n"); + + /* Request a shared interrupt line. */ + error = request_irq (dev->irq, RCinterrupt, SA_SHIRQ, dev->name, dev); + if (error) { + printk (KERN_ERR "(rcpci45 driver:) %s: unable to get IRQ %d\n", + dev->name, dev->irq); + goto err_out; + } + + error = RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback, + (PFNRXCALLBACK) RCrecv_callback, + (PFNCALLBACK) RCreboot_callback); + if (error) { + printk (KERN_ERR + "(rcpci45 driver:) Unable to initialize msg layer\n"); + goto err_out_free_irq; + } + if ((error = RCGetMAC (dev, NULL))) { + printk (KERN_ERR + "(rcpci45 driver:) Unable to get adapter MAC\n"); + goto err_out_free_irq; + } + + DriverControlWord |= WARM_REBOOT_CAPABLE; + RCReportDriverCapability (dev, DriverControlWord); + + printk (KERN_INFO "%s: RedCreek Communications IPSEC VPN adapter\n", + dev->name); + + /* RAA: Old RCopen starts here */ + RCEnableI2OInterrupts (dev); + + /* RAA Hmm, how does the comment below jibe with the newly imported + * code above? A FIXME!!*/ + if (pDpa->nexus) { + /* This is not the first time RCopen is called. Thus, + * the interface was previously opened and later closed + * by RCclose(). RCclose() does a Shutdown; to wake up + * the adapter, a reset is mandatory before we can post + * receive buffers. However, if the adapter initiated + * a reboot while the interface was closed -- and interrupts + * were turned off -- we need will need to reinitialize + * the adapter, rather than simply waking it up. + */ + dprintk (KERN_INFO "Waking up adapter...\n"); + RCResetLANCard (dev, 0, 0, 0); + } else + pDpa->nexus = 1; + + while (post_buffers) { + if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG) + requested = MAX_NMBR_POST_BUFFERS_PER_MSG; + else + requested = post_buffers; + count = RC_allocate_and_post_buffers (dev, requested); + + if (count < requested) { + /* + * Check to see if we were able to post any buffers at all. + */ + if (post_buffers == MAX_NMBR_RCV_BUFFERS) { + printk (KERN_ERR + "(rcpci45 driver:) Error RCopen: not able to allocate any buffers\r\n"); + return (-ENOMEM); + } + printk (KERN_WARNING + "(rcpci45 driver:) Warning RCopen: not able to allocate all requested buffers\r\n"); + break; /* we'll try to post more buffers later */ + } else + post_buffers -= count; + } + pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers; + pDpa->shutdown = 0; /* just in case */ + dprintk ("RCopen: posted %d buffers\n", (uint) pDpa->numOutRcvBuffers); + MOD_INC_USE_COUNT; + netif_start_queue (dev); + return 0; + +err_out_free_irq: + free_irq (dev->irq, dev); +err_out: + return error; } static int -RC_xmit_packet(struct sk_buff *skb, struct net_device *dev) +RC_xmit_packet (struct sk_buff *skb, struct net_device *dev) { - PDPA pDpa = dev->priv; - singleTCB tcb; - psingleTCB ptcb = &tcb; - RC_RETURN status = 0; - - netif_stop_queue(dev); - - if (pDpa->shutdown || pDpa->reboot) { - dprintk("RC_xmit_packet: tbusy!\n"); - return 1; - } - - /* - * The user is free to reuse the TCB after RCI2OSendPacket() returns, since - * the function copies the necessary info into its own private space. Thus, - * our TCB can be a local structure. The skb, on the other hand, will be - * freed up in our interrupt handler. - */ - - ptcb->bcount = 1; - - /* - * we'll get the context when the adapter interrupts us to tell us that - * the transmission is done. At that time, we can free skb. - */ - ptcb->b.context = (U32)skb; - ptcb->b.scount = 1; - ptcb->b.size = skb->len; - ptcb->b.addr = virt_to_bus((void *)skb->data); - - dprintk("RC xmit: skb = 0x%x, pDpa = 0x%x, id = %d, ptcb = 0x%x\n", - (uint)skb, (uint)pDpa, (uint)pDpa->id, (uint)ptcb); - if ( (status = RCI2OSendPacket(dev, (U32)NULL, (PRCTCB)ptcb)) - != RC_RTN_NO_ERROR) { - dprintk("RC send error 0x%x\n", (uint)status); - return 1; - } else { - dev->trans_start = jiffies; - netif_wake_queue(dev); - } - /* - * That's it! - */ - return 0; + PDPA pDpa = dev->priv; + singleTCB tcb; + psingleTCB ptcb = &tcb; + RC_RETURN status = 0; + + netif_stop_queue (dev); + + if (pDpa->shutdown || pDpa->reboot) { + dprintk ("RC_xmit_packet: tbusy!\n"); + return 1; + } + + /* + * The user is free to reuse the TCB after RCI2OSendPacket() returns, since + * the function copies the necessary info into its own private space. Thus, + * our TCB can be a local structure. The skb, on the other hand, will be + * freed up in our interrupt handler. + */ + + ptcb->bcount = 1; + + /* + * we'll get the context when the adapter interrupts us to tell us that + * the transmission is done. At that time, we can free skb. + */ + ptcb->b.context = (U32) skb; + ptcb->b.scount = 1; + ptcb->b.size = skb->len; + ptcb->b.addr = virt_to_bus ((void *) skb->data); + + dprintk ("RC xmit: skb = 0x%x, pDpa = 0x%x, id = %d, ptcb = 0x%x\n", + (uint) skb, (uint) pDpa, (uint) pDpa->id, (uint) ptcb); + if ((status = RCI2OSendPacket (dev, (U32) NULL, (PRCTCB) ptcb)) + != RC_RTN_NO_ERROR) { + dprintk ("RC send error 0x%x\n", (uint) status); + return 1; + } else { + dev->trans_start = jiffies; + netif_wake_queue (dev); + } + /* + * That's it! + */ + return 0; } /* @@ -423,107 +431,110 @@ RC_xmit_packet(struct sk_buff *skb, struct net_device *dev) * RC_RESOURCE_RETURN_PEND_TX_BUFFERS flag. * All we need to do is free the buffers. */ -static void -RCxmit_callback(U32 Status, - U16 PcktCount, - PU32 BufferContext, - struct net_device *dev) +static void +RCxmit_callback (U32 Status, + U16 PcktCount, PU32 BufferContext, struct net_device *dev) { - struct sk_buff *skb; - PDPA pDpa = dev->priv; + struct sk_buff *skb; + PDPA pDpa = dev->priv; - if (!pDpa) { - printk(KERN_ERR "(rcpci45 driver:) Fatal error: xmit callback, !pDpa\n"); - return; - } + if (!pDpa) { + printk (KERN_ERR + "(rcpci45 driver:) Fatal error: xmit callback, !pDpa\n"); + return; + } /* dprintk("xmit_callback: Status = 0x%x\n", (uint)Status); */ - if (Status != I2O_REPLY_STATUS_SUCCESS) - dprintk("xmit_callback: Status = 0x%x\n", (uint)Status); - if (pDpa->shutdown || pDpa->reboot) - dprintk("xmit callback: shutdown||reboot\n"); - - dprintk("xmit_callback: PcktCount = %d, BC = 0x%x\n", - (uint)PcktCount, (uint)BufferContext); - - while (PcktCount--) { - skb = (struct sk_buff *)(BufferContext[0]); - dprintk("skb = 0x%x\n", (uint)skb); - BufferContext++; - dev_kfree_skb_irq(skb); - } - netif_wake_queue(dev); + if (Status != I2O_REPLY_STATUS_SUCCESS) + dprintk ("xmit_callback: Status = 0x%x\n", (uint) Status); + if (pDpa->shutdown || pDpa->reboot) + dprintk ("xmit callback: shutdown||reboot\n"); + + dprintk ("xmit_callback: PcktCount = %d, BC = 0x%x\n", + (uint) PcktCount, (uint) BufferContext); + + while (PcktCount--) { + skb = (struct sk_buff *) (BufferContext[0]); + dprintk ("skb = 0x%x\n", (uint) skb); + BufferContext++; + dev_kfree_skb_irq (skb); + } + netif_wake_queue (dev); } static void -RCreset_callback(U32 Status, U32 p1, U32 p2, struct net_device *dev) +RCreset_callback (U32 Status, U32 p1, U32 p2, struct net_device *dev) { - PDPA pDpa = dev->priv; - - dprintk("RCreset_callback Status 0x%x\n", (uint)Status); - /* - * Check to see why we were called. - */ - if (pDpa->shutdown) { - printk(KERN_INFO "(rcpci45 driver:) Shutting down interface\n"); - pDpa->shutdown = 0; - pDpa->reboot = 0; - MOD_DEC_USE_COUNT; - } else if (pDpa->reboot) { - printk(KERN_INFO "(rcpci45 driver:) reboot, shutdown adapter\n"); - /* - * We don't set any of the flags in RCShutdownLANCard() - * and we don't pass a callback routine to it. - * The adapter will have already initiated the reboot by - * the time the function returns. - */ - RCDisableI2OInterrupts(dev); - RCShutdownLANCard(dev,0,0,0); - printk(KERN_INFO "(rcpci45 driver:) scheduling timer...\n"); - init_timer(&pDpa->timer); - pDpa->timer.expires = RUN_AT((40*HZ)/10); /* 4 sec. */ - pDpa->timer.data = (unsigned long)dev; - pDpa->timer.function = &rc_timer; /* timer handler */ - add_timer(&pDpa->timer); - } + PDPA pDpa = dev->priv; + + dprintk ("RCreset_callback Status 0x%x\n", (uint) Status); + /* + * Check to see why we were called. + */ + if (pDpa->shutdown) { + printk (KERN_INFO + "(rcpci45 driver:) Shutting down interface\n"); + pDpa->shutdown = 0; + pDpa->reboot = 0; + MOD_DEC_USE_COUNT; + } else if (pDpa->reboot) { + printk (KERN_INFO + "(rcpci45 driver:) reboot, shutdown adapter\n"); + /* + * We don't set any of the flags in RCShutdownLANCard() + * and we don't pass a callback routine to it. + * The adapter will have already initiated the reboot by + * the time the function returns. + */ + RCDisableI2OInterrupts (dev); + RCShutdownLANCard (dev, 0, 0, 0); + printk (KERN_INFO "(rcpci45 driver:) scheduling timer...\n"); + init_timer (&pDpa->timer); + pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); /* 4 sec. */ + pDpa->timer.data = (unsigned long) dev; + pDpa->timer.function = &rc_timer; /* timer handler */ + add_timer (&pDpa->timer); + } } static void -RCreboot_callback(U32 Status, U32 p1, U32 p2, struct net_device *dev) +RCreboot_callback (U32 Status, U32 p1, U32 p2, struct net_device *dev) { - PDPA pDpa = dev->priv; - - dprintk("RCreboot: rcv buffers outstanding = %d\n", - (uint)pDpa->numOutRcvBuffers); - - if (pDpa->shutdown) { - printk(KERN_INFO "(rcpci45 driver:) skipping reboot sequence -- shutdown already initiated\n"); - return; - } - pDpa->reboot = 1; - /* - * OK, we reset the adapter and ask it to return all - * outstanding transmit buffers as well as the posted - * receive buffers. When the adapter is done returning - * those buffers, it will call our RCreset_callback() - * routine. In that routine, we'll call RCShutdownLANCard() - * to tell the adapter that it's OK to start the reboot and - * schedule a timer callback routine to execute 3 seconds - * later; this routine will reinitialize the adapter at that time. - */ - RCResetLANCard(dev, RC_RESOURCE_RETURN_POSTED_RX_BUCKETS | - RC_RESOURCE_RETURN_PEND_TX_BUFFERS,0, - (PFNCALLBACK)RCreset_callback); -} + PDPA pDpa = dev->priv; + dprintk ("RCreboot: rcv buffers outstanding = %d\n", + (uint) pDpa->numOutRcvBuffers); + + if (pDpa->shutdown) { + printk (KERN_INFO + "(rcpci45 driver:) skipping reboot sequence -- shutdown already initiated\n"); + return; + } + pDpa->reboot = 1; + /* + * OK, we reset the adapter and ask it to return all + * outstanding transmit buffers as well as the posted + * receive buffers. When the adapter is done returning + * those buffers, it will call our RCreset_callback() + * routine. In that routine, we'll call RCShutdownLANCard() + * to tell the adapter that it's OK to start the reboot and + * schedule a timer callback routine to execute 3 seconds + * later; this routine will reinitialize the adapter at that time. + */ + RCResetLANCard (dev, RC_RESOURCE_RETURN_POSTED_RX_BUCKETS | + RC_RESOURCE_RETURN_PEND_TX_BUFFERS, 0, + (PFNCALLBACK) RCreset_callback); +} -int broadcast_packet(unsigned char * address) +int +broadcast_packet (unsigned char *address) { - int i; - for (i=0; i<6; i++) - if (address[i] != 0xff) return 0; + int i; + for (i = 0; i < 6; i++) + if (address[i] != 0xff) + return 0; - return 1; + return 1; } /* @@ -534,124 +545,119 @@ int broadcast_packet(unsigned char * address) * filled (one ethernet packet per buffer). */ static void -RCrecv_callback(U32 Status, - U8 PktCount, - U32 BucketsRemain, - PU32 PacketDescBlock, - struct net_device *dev) +RCrecv_callback (U32 Status, + U8 PktCount, + U32 BucketsRemain, + PU32 PacketDescBlock, struct net_device *dev) { - U32 len, count; - PDPA pDpa = dev->priv; - struct sk_buff *skb; - singleTCB tcb; - psingleTCB ptcb = &tcb; - - - ptcb->bcount = 1; - - dprintk("RCrecv_callback: 0x%x, 0x%x, 0x%x\n", - (uint)PktCount, (uint)BucketsRemain, (uint)PacketDescBlock); - - if ((pDpa->shutdown || pDpa->reboot) && !Status) - dprintk("shutdown||reboot && !Status: PktCount = %d\n",PktCount); - - if ( (Status != I2O_REPLY_STATUS_SUCCESS) || pDpa->shutdown) - { - /* - * Free whatever buffers the adapter returned, but don't - * pass them to the kernel. - */ - - if (!pDpa->shutdown && !pDpa->reboot) - printk(KERN_INFO "(rcpci45 driver:) RCrecv error: status = 0x%x\n", (uint)Status); - else - dprintk("Returning %d buffers, status = 0x%x\n", - PktCount, (uint)Status); - /* - * TO DO: check the nature of the failure and put the adapter in - * failed mode if it's a hard failure. Send a reset to the adapter - * and free all outstanding memory. - */ - if (Status == I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER) - dprintk("RCrecv status ABORT NO DATA TRANSFER\n"); - - /* check for reset status: I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER */ - if (PacketDescBlock) - { - while(PktCount--) - { - skb = (struct sk_buff *)PacketDescBlock[0]; - dprintk("free skb 0x%p\n", skb); - dev_kfree_skb (skb); - pDpa->numOutRcvBuffers--; - PacketDescBlock += BD_SIZE; /* point to next context field */ - } - } - return; - } - else - { - while(PktCount--) - { - skb = (struct sk_buff *)PacketDescBlock[0]; - if (pDpa->shutdown) - dprintk("shutdown: skb=0x%x\n", (uint)skb); - - dprintk("skb = 0x%x: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", (uint)skb, - (uint)skb->data[0], (uint)skb->data[1], (uint)skb->data[2], - (uint)skb->data[3], (uint)skb->data[4], (uint)skb->data[5]); - -#ifdef PROMISCUOUS_BY_DEFAULT /* early 2.x firmware */ - if ( (memcmp(dev->dev_addr, skb->data, 6)) && - (!broadcast_packet(skb->data))) - { - /* - * Re-post the buffer to the adapter. Since the adapter usually - * return 1 to 2 receive buffers at a time, it's not too inefficient - * post one buffer at a time but ... may be that should be - * optimized at some point. - */ - ptcb->b.context = (U32)skb; - ptcb->b.scount = 1; - ptcb->b.size = MAX_ETHER_SIZE; - ptcb->b.addr = virt_to_bus((void *)skb->data); - - if ( RCPostRecvBuffers(dev, (PRCTCB)ptcb ) != RC_RTN_NO_ERROR) - { - printk(KERN_WARNING "(rcpci45 driver:) RCrecv_callback: post buffer failed!\n"); - dev_kfree_skb (skb); - } - else - pDpa->numOutRcvBuffers++; - } - else -#endif /* PROMISCUOUS_BY_DEFAULT */ - { - len = PacketDescBlock[2]; - skb->dev = dev; - skb_put( skb, len ); /* adjust length and tail */ - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); /* send the packet to the kernel */ - dev->last_rx = jiffies; - } - pDpa->numOutRcvBuffers--; - PacketDescBlock += BD_SIZE; /* point to next context field */ - } - } - - /* - * Replenish the posted receive buffers. - * DO NOT replenish buffers if the driver has already - * initiated a reboot or shutdown! - */ - - if (!pDpa->shutdown && !pDpa->reboot) - { - count = RC_allocate_and_post_buffers(dev, - MAX_NMBR_RCV_BUFFERS-pDpa->numOutRcvBuffers); - pDpa->numOutRcvBuffers += count; - } + U32 len, count; + PDPA pDpa = dev->priv; + struct sk_buff *skb; + singleTCB tcb; + psingleTCB ptcb = &tcb; + + ptcb->bcount = 1; + + dprintk ("RCrecv_callback: 0x%x, 0x%x, 0x%x\n", + (uint) PktCount, (uint) BucketsRemain, (uint) PacketDescBlock); + + if ((pDpa->shutdown || pDpa->reboot) && !Status) + dprintk ("shutdown||reboot && !Status: PktCount = %d\n", + PktCount); + + if ((Status != I2O_REPLY_STATUS_SUCCESS) || pDpa->shutdown) { + /* + * Free whatever buffers the adapter returned, but don't + * pass them to the kernel. + */ + + if (!pDpa->shutdown && !pDpa->reboot) + printk (KERN_INFO + "(rcpci45 driver:) RCrecv error: status = 0x%x\n", + (uint) Status); + else + dprintk ("Returning %d buffers, status = 0x%x\n", + PktCount, (uint) Status); + /* + * TO DO: check the nature of the failure and put the adapter in + * failed mode if it's a hard failure. Send a reset to the adapter + * and free all outstanding memory. + */ + if (Status == I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER) + dprintk ("RCrecv status ABORT NO DATA TRANSFER\n"); + + /* check for reset status: I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER */ + if (PacketDescBlock) { + while (PktCount--) { + skb = (struct sk_buff *) PacketDescBlock[0]; + dprintk ("free skb 0x%p\n", skb); + dev_kfree_skb (skb); + pDpa->numOutRcvBuffers--; + PacketDescBlock += BD_SIZE; /* point to next context field */ + } + } + return; + } else { + while (PktCount--) { + skb = (struct sk_buff *) PacketDescBlock[0]; + if (pDpa->shutdown) + dprintk ("shutdown: skb=0x%x\n", (uint) skb); + + dprintk ("skb = 0x%x: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + (uint) skb, (uint) skb->data[0], + (uint) skb->data[1], (uint) skb->data[2], + (uint) skb->data[3], (uint) skb->data[4], + (uint) skb->data[5]); + +#ifdef PROMISCUOUS_BY_DEFAULT /* early 2.x firmware */ + if ((memcmp (dev->dev_addr, skb->data, 6)) && + (!broadcast_packet (skb->data))) { + /* + * Re-post the buffer to the adapter. Since the adapter usually + * return 1 to 2 receive buffers at a time, it's not too inefficient + * post one buffer at a time but ... may be that should be + * optimized at some point. + */ + ptcb->b.context = (U32) skb; + ptcb->b.scount = 1; + ptcb->b.size = MAX_ETHER_SIZE; + ptcb->b.addr = virt_to_bus ((void *) skb->data); + + if (RCPostRecvBuffers (dev, (PRCTCB) ptcb) != + RC_RTN_NO_ERROR) { + printk (KERN_WARNING + "(rcpci45 driver:) RCrecv_callback: post buffer failed!\n"); + dev_kfree_skb (skb); + } else + pDpa->numOutRcvBuffers++; + } else +#endif /* PROMISCUOUS_BY_DEFAULT */ + { + len = PacketDescBlock[2]; + skb->dev = dev; + skb_put (skb, len); /* adjust length and tail */ + skb->protocol = eth_type_trans (skb, dev); + netif_rx (skb); /* send the packet to the kernel */ + dev->last_rx = jiffies; + } + pDpa->numOutRcvBuffers--; + PacketDescBlock += BD_SIZE; /* point to next context field */ + } + } + + /* + * Replenish the posted receive buffers. + * DO NOT replenish buffers if the driver has already + * initiated a reboot or shutdown! + */ + + if (!pDpa->shutdown && !pDpa->reboot) { + count = RC_allocate_and_post_buffers (dev, + MAX_NMBR_RCV_BUFFERS - + pDpa->numOutRcvBuffers); + pDpa->numOutRcvBuffers += count; + } } @@ -663,474 +669,533 @@ RCrecv_callback(U32 Status, * RCProcI2OMsgQ(), which in turn process the message and * calls one of our callback functions. */ -static void -RCinterrupt(int irq, void *dev_id, struct pt_regs *regs) +static void +RCinterrupt (int irq, void *dev_id, struct pt_regs *regs) { - PDPA pDpa; - struct net_device *dev = dev_id; + PDPA pDpa; + struct net_device *dev = dev_id; - pDpa = dev->priv; - - if (pDpa->shutdown) - dprintk("shutdown: service irq\n"); + pDpa = dev->priv; - dprintk("RC irq: pDpa = 0x%x, dev = 0x%x, id = %d\n", - (uint)pDpa, (uint)dev, (uint)pDpa->id); - dprintk("dev = 0x%x\n", (uint)dev); + if (pDpa->shutdown) + dprintk ("shutdown: service irq\n"); - RCProcI2OMsgQ(dev); -} + dprintk ("RC irq: pDpa = 0x%x, dev = 0x%x, id = %d\n", + (uint) pDpa, (uint) dev, (uint) pDpa->id); + dprintk ("dev = 0x%x\n", (uint) dev); + RCProcI2OMsgQ (dev); +} #define REBOOT_REINIT_RETRY_LIMIT 4 -static void rc_timer(unsigned long data) +static void +rc_timer (unsigned long data) { - struct net_device *dev = (struct net_device *)data; - PDPA pDpa = dev->priv; - int init_status; - static int retry; - int post_buffers = MAX_NMBR_RCV_BUFFERS; - int count = 0; - int requested = 0; - - if (pDpa->reboot) - { - init_status = RCInitI2OMsgLayer(dev, (PFNTXCALLBACK)RCxmit_callback, - (PFNRXCALLBACK)RCrecv_callback, - (PFNCALLBACK)RCreboot_callback); - - switch(init_status) - { - case RC_RTN_NO_ERROR: - - pDpa->reboot = 0; - pDpa->shutdown = 0; /* just in case */ - RCReportDriverCapability(dev, DriverControlWord); - RCEnableI2OInterrupts(dev); - - if (dev->flags & IFF_UP) - { - while(post_buffers) - { - if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG) - requested = MAX_NMBR_POST_BUFFERS_PER_MSG; - else - requested = post_buffers; - count = RC_allocate_and_post_buffers(dev, requested); - post_buffers -= count; - if ( count < requested ) - break; - } - pDpa->numOutRcvBuffers = - MAX_NMBR_RCV_BUFFERS - post_buffers; - dprintk("rc: posted %d buffers \r\n", - (uint)pDpa->numOutRcvBuffers); - } - dprintk("Initialization done.\n"); - netif_wake_queue(dev); - retry=0; - return; - case RC_RTN_FREE_Q_EMPTY: - retry++; - printk(KERN_WARNING "(rcpci45 driver:) inbound free q empty\n"); - break; - default: - retry++; - printk(KERN_WARNING "(rcpci45 driver:) bad status after reboot: %d\n", init_status); - break; - } - - if (retry > REBOOT_REINIT_RETRY_LIMIT) - { - printk(KERN_WARNING "(rcpci45 driver:) unable to reinitialize adapter after reboot\n"); - printk(KERN_WARNING "(rcpci45 driver:) decrementing driver and closing interface\n"); - RCDisableI2OInterrupts(dev); - dev->flags &= ~IFF_UP; - MOD_DEC_USE_COUNT; - } - else - { - printk(KERN_INFO "(rcpci45 driver:) rescheduling timer...\n"); - init_timer(&pDpa->timer); - pDpa->timer.expires = RUN_AT((40*HZ)/10); /* 3 sec. */ - pDpa->timer.data = (unsigned long)dev; - pDpa->timer.function = &rc_timer; /* timer handler */ - add_timer(&pDpa->timer); - } - } - else - printk(KERN_WARNING "(rcpci45 driver:) timer??\n"); + struct net_device *dev = (struct net_device *) data; + PDPA pDpa = dev->priv; + int init_status; + static int retry; + int post_buffers = MAX_NMBR_RCV_BUFFERS; + int count = 0; + int requested = 0; + + if (pDpa->reboot) { + init_status = + RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback, + (PFNRXCALLBACK) RCrecv_callback, + (PFNCALLBACK) RCreboot_callback); + + switch (init_status) { + case RC_RTN_NO_ERROR: + + pDpa->reboot = 0; + pDpa->shutdown = 0; /* just in case */ + RCReportDriverCapability (dev, DriverControlWord); + RCEnableI2OInterrupts (dev); + + if (dev->flags & IFF_UP) { + while (post_buffers) { + if (post_buffers > + MAX_NMBR_POST_BUFFERS_PER_MSG) + requested = + MAX_NMBR_POST_BUFFERS_PER_MSG; + else + requested = post_buffers; + count = + RC_allocate_and_post_buffers (dev, + requested); + post_buffers -= count; + if (count < requested) + break; + } + pDpa->numOutRcvBuffers = + MAX_NMBR_RCV_BUFFERS - post_buffers; + dprintk ("rc: posted %d buffers \r\n", + (uint) pDpa->numOutRcvBuffers); + } + dprintk ("Initialization done.\n"); + netif_wake_queue (dev); + retry = 0; + return; + case RC_RTN_FREE_Q_EMPTY: + retry++; + printk (KERN_WARNING + "(rcpci45 driver:) inbound free q empty\n"); + break; + default: + retry++; + printk (KERN_WARNING + "(rcpci45 driver:) bad status after reboot: %d\n", + init_status); + break; + } + + if (retry > REBOOT_REINIT_RETRY_LIMIT) { + printk (KERN_WARNING + "(rcpci45 driver:) unable to reinitialize adapter after reboot\n"); + printk (KERN_WARNING + "(rcpci45 driver:) decrementing driver and closing interface\n"); + RCDisableI2OInterrupts (dev); + dev->flags &= ~IFF_UP; + MOD_DEC_USE_COUNT; + } else { + printk (KERN_INFO + "(rcpci45 driver:) rescheduling timer...\n"); + init_timer (&pDpa->timer); + pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); /* 3 sec. */ + pDpa->timer.data = (unsigned long) dev; + pDpa->timer.function = &rc_timer; /* timer handler */ + add_timer (&pDpa->timer); + } + } else + printk (KERN_WARNING "(rcpci45 driver:) timer??\n"); } static int -RCclose(struct net_device *dev) +RCclose (struct net_device *dev) { - PDPA pDpa = dev->priv; - - netif_stop_queue(dev); - - dprintk("RCclose\r\n"); - - if (pDpa->reboot) - { - printk(KERN_INFO "(rcpci45 driver:) skipping reset -- adapter already in reboot mode\n"); - dev->flags &= ~IFF_UP; - pDpa->shutdown = 1; - return 0; - } - dprintk("receive buffers outstanding: %d\n", (uint)pDpa->numOutRcvBuffers); - - pDpa->shutdown = 1; - - /* - * We can't allow the driver to be unloaded until the adapter returns - * all posted receive buffers. It doesn't hurt to tell the adapter - * to return all posted receive buffers and outstanding xmit buffers, - * even if there are none. - */ - - RCShutdownLANCard(dev, RC_RESOURCE_RETURN_POSTED_RX_BUCKETS | - RC_RESOURCE_RETURN_PEND_TX_BUFFERS,0, - (PFNCALLBACK)RCreset_callback); - - dev->flags &= ~IFF_UP; - return 0; + PDPA pDpa = dev->priv; + + netif_stop_queue (dev); + + dprintk ("RCclose\r\n"); + + if (pDpa->reboot) { + printk (KERN_INFO + "(rcpci45 driver:) skipping reset -- adapter already in reboot mode\n"); + dev->flags &= ~IFF_UP; + pDpa->shutdown = 1; + return 0; + } + dprintk ("receive buffers outstanding: %d\n", + (uint) pDpa->numOutRcvBuffers); + + pDpa->shutdown = 1; + + /* + * We can't allow the driver to be unloaded until the adapter returns + * all posted receive buffers. It doesn't hurt to tell the adapter + * to return all posted receive buffers and outstanding xmit buffers, + * even if there are none. + */ + + RCShutdownLANCard (dev, RC_RESOURCE_RETURN_POSTED_RX_BUCKETS | + RC_RESOURCE_RETURN_PEND_TX_BUFFERS, 0, + (PFNCALLBACK) RCreset_callback); + + dev->flags &= ~IFF_UP; + return 0; } static struct net_device_stats * -RCget_stats(struct net_device *dev) +RCget_stats (struct net_device *dev) { - RCLINKSTATS RCstats; - - PDPA pDpa = dev->priv; - - if (!pDpa) - { - dprintk("RCget_stats: !pDpa\n"); - return 0; - } - else if (!(dev->flags & IFF_UP)) - { - dprintk("RCget_stats: device down\n"); - return 0; - } - - memset(&RCstats, 0, sizeof(RCLINKSTATS)); - if ( (RCGetLinkStatistics(dev, &RCstats, (void *)0)) == RC_RTN_NO_ERROR ) - { - dprintk("TX_good 0x%x\n", (uint)RCstats.TX_good); - dprintk("TX_maxcol 0x%x\n", (uint)RCstats.TX_maxcol); - dprintk("TX_latecol 0x%x\n", (uint)RCstats.TX_latecol); - dprintk("TX_urun 0x%x\n", (uint)RCstats.TX_urun); - dprintk("TX_crs 0x%x\n", (uint)RCstats.TX_crs); - dprintk("TX_def 0x%x\n", (uint)RCstats.TX_def); - dprintk("TX_singlecol 0x%x\n", (uint)RCstats.TX_singlecol); - dprintk("TX_multcol 0x%x\n", (uint)RCstats.TX_multcol); - dprintk("TX_totcol 0x%x\n", (uint)RCstats.TX_totcol); - - dprintk("Rcv_good 0x%x\n", (uint)RCstats.Rcv_good); - dprintk("Rcv_CRCerr 0x%x\n", (uint)RCstats.Rcv_CRCerr); - dprintk("Rcv_alignerr 0x%x\n", (uint)RCstats.Rcv_alignerr); - dprintk("Rcv_reserr 0x%x\n", (uint)RCstats.Rcv_reserr); - dprintk("Rcv_orun 0x%x\n", (uint)RCstats.Rcv_orun); - dprintk("Rcv_cdt 0x%x\n", (uint)RCstats.Rcv_cdt); - dprintk("Rcv_runt 0x%x\n", (uint)RCstats.Rcv_runt); - - pDpa->stats.rx_packets = RCstats.Rcv_good; /* total packets received */ - pDpa->stats.tx_packets = RCstats.TX_good; /* total packets transmitted */ - - pDpa->stats.rx_errors = - RCstats.Rcv_CRCerr + - RCstats.Rcv_alignerr + - RCstats.Rcv_reserr + - RCstats.Rcv_orun + - RCstats.Rcv_cdt + - RCstats.Rcv_runt; /* bad packets received */ - - pDpa->stats.tx_errors = - RCstats.TX_urun + - RCstats.TX_crs + - RCstats.TX_def + - RCstats.TX_totcol; /* packet transmit problems */ - - /* - * This needs improvement. - */ - pDpa->stats.rx_dropped = 0; /* no space in linux buffers */ - pDpa->stats.tx_dropped = 0; /* no space available in linux */ - pDpa->stats.multicast = 0; /* multicast packets received */ - pDpa->stats.collisions = RCstats.TX_totcol; - - /* detailed rx_errors: */ - pDpa->stats.rx_length_errors = 0; - pDpa->stats.rx_over_errors = RCstats.Rcv_orun; /* receiver ring buff overflow */ - pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr; /* recved pkt with crc error */ - pDpa->stats.rx_frame_errors = 0; /* recv'd frame alignment error */ - pDpa->stats.rx_fifo_errors = 0; /* recv'r fifo overrun */ - pDpa->stats.rx_missed_errors = 0; /* receiver missed packet */ - - /* detailed tx_errors */ - pDpa->stats.tx_aborted_errors = 0; - pDpa->stats.tx_carrier_errors = 0; - pDpa->stats.tx_fifo_errors = 0; - pDpa->stats.tx_heartbeat_errors = 0; - pDpa->stats.tx_window_errors = 0; - - return ((struct net_device_stats *)&(pDpa->stats)); - } - return 0; + RCLINKSTATS RCstats; + + PDPA pDpa = dev->priv; + + if (!pDpa) { + dprintk ("RCget_stats: !pDpa\n"); + return 0; + } else if (!(dev->flags & IFF_UP)) { + dprintk ("RCget_stats: device down\n"); + return 0; + } + + memset (&RCstats, 0, sizeof (RCLINKSTATS)); + if ((RCGetLinkStatistics (dev, &RCstats, (void *) 0)) == + RC_RTN_NO_ERROR) { + dprintk ("TX_good 0x%x\n", (uint) RCstats.TX_good); + dprintk ("TX_maxcol 0x%x\n", (uint) RCstats.TX_maxcol); + dprintk ("TX_latecol 0x%x\n", (uint) RCstats.TX_latecol); + dprintk ("TX_urun 0x%x\n", (uint) RCstats.TX_urun); + dprintk ("TX_crs 0x%x\n", (uint) RCstats.TX_crs); + dprintk ("TX_def 0x%x\n", (uint) RCstats.TX_def); + dprintk ("TX_singlecol 0x%x\n", (uint) RCstats.TX_singlecol); + dprintk ("TX_multcol 0x%x\n", (uint) RCstats.TX_multcol); + dprintk ("TX_totcol 0x%x\n", (uint) RCstats.TX_totcol); + + dprintk ("Rcv_good 0x%x\n", (uint) RCstats.Rcv_good); + dprintk ("Rcv_CRCerr 0x%x\n", (uint) RCstats.Rcv_CRCerr); + dprintk ("Rcv_alignerr 0x%x\n", (uint) RCstats.Rcv_alignerr); + dprintk ("Rcv_reserr 0x%x\n", (uint) RCstats.Rcv_reserr); + dprintk ("Rcv_orun 0x%x\n", (uint) RCstats.Rcv_orun); + dprintk ("Rcv_cdt 0x%x\n", (uint) RCstats.Rcv_cdt); + dprintk ("Rcv_runt 0x%x\n", (uint) RCstats.Rcv_runt); + + pDpa->stats.rx_packets = RCstats.Rcv_good; /* total packets received */ + pDpa->stats.tx_packets = RCstats.TX_good; /* total packets transmitted */ + + pDpa->stats.rx_errors = RCstats.Rcv_CRCerr + RCstats.Rcv_alignerr + RCstats.Rcv_reserr + RCstats.Rcv_orun + RCstats.Rcv_cdt + RCstats.Rcv_runt; /* bad packets received */ + + pDpa->stats.tx_errors = RCstats.TX_urun + RCstats.TX_crs + RCstats.TX_def + RCstats.TX_totcol; /* packet transmit problems */ + + /* + * This needs improvement. + */ + pDpa->stats.rx_dropped = 0; /* no space in linux buffers */ + pDpa->stats.tx_dropped = 0; /* no space available in linux */ + pDpa->stats.multicast = 0; /* multicast packets received */ + pDpa->stats.collisions = RCstats.TX_totcol; + + /* detailed rx_errors: */ + pDpa->stats.rx_length_errors = 0; + pDpa->stats.rx_over_errors = RCstats.Rcv_orun; /* receiver ring buff overflow */ + pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr; /* recved pkt with crc error */ + pDpa->stats.rx_frame_errors = 0; /* recv'd frame alignment error */ + pDpa->stats.rx_fifo_errors = 0; /* recv'r fifo overrun */ + pDpa->stats.rx_missed_errors = 0; /* receiver missed packet */ + + /* detailed tx_errors */ + pDpa->stats.tx_aborted_errors = 0; + pDpa->stats.tx_carrier_errors = 0; + pDpa->stats.tx_fifo_errors = 0; + pDpa->stats.tx_heartbeat_errors = 0; + pDpa->stats.tx_window_errors = 0; + + return ((struct net_device_stats *) &(pDpa->stats)); + } + return 0; } -static int RCioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int +RCioctl (struct net_device *dev, struct ifreq *rq, int cmd) { - RCuser_struct RCuser; - PDPA pDpa = dev->priv; - - dprintk("RCioctl: cmd = 0x%x\n", cmd); - - if(!capable(CAP_NET_ADMIN)) - return -EPERM; - - switch (cmd) { - - case RCU_PROTOCOL_REV: - /* - * Assign user protocol revision, to tell user-level - * controller program whether or not it's in sync. - */ - rq->ifr_ifru.ifru_data = (caddr_t) USER_PROTOCOL_REV; - break; - - - case RCU_COMMAND: - { - if(copy_from_user(&RCuser, rq->ifr_data, sizeof(RCuser))) - return -EFAULT; - - dprintk("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd); - - switch(RCuser.cmd) - { - case RCUC_GETFWVER: - printk(KERN_INFO "(rcpci45 driver:) RC GETFWVER\n"); - RCUD_GETFWVER = &RCuser.RCUS_GETFWVER; - RCGetFirmwareVer(dev, (PU8) &RCUD_GETFWVER->FirmString, NULL); - break; - case RCUC_GETINFO: - printk(KERN_INFO "(rcpci45 driver:) RC GETINFO\n"); - RCUD_GETINFO = &RCuser.RCUS_GETINFO; - RCUD_GETINFO -> mem_start = dev->base_addr; - RCUD_GETINFO -> mem_end = dev->base_addr + pDpa->pci_addr_len; - RCUD_GETINFO -> base_addr = pDpa->pci_addr; - RCUD_GETINFO -> irq = dev->irq; - break; - case RCUC_GETIPANDMASK: - printk(KERN_INFO "(rcpci45 driver:) RC GETIPANDMASK\n"); - RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK; - RCGetRavlinIPandMask(dev, (PU32) &RCUD_GETIPANDMASK->IpAddr, - (PU32) &RCUD_GETIPANDMASK->NetMask, NULL); - break; - case RCUC_GETLINKSTATISTICS: - printk(KERN_INFO "(rcpci45 driver:) RC GETLINKSTATISTICS\n"); - RCUD_GETLINKSTATISTICS = &RCuser.RCUS_GETLINKSTATISTICS; - RCGetLinkStatistics(dev, (P_RCLINKSTATS) &RCUD_GETLINKSTATISTICS->StatsReturn, NULL); - break; - case RCUC_GETLINKSTATUS: - printk(KERN_INFO "(rcpci45 driver:) RC GETLINKSTATUS\n"); - RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS; - RCGetLinkStatus(dev, (PU32) &RCUD_GETLINKSTATUS->ReturnStatus, NULL); - break; - case RCUC_GETMAC: - printk(KERN_INFO "(rcpci45 driver:) RC GETMAC\n"); - RCUD_GETMAC = &RCuser.RCUS_GETMAC; - RCGetMAC(dev, NULL); - break; - case RCUC_GETPROM: - printk(KERN_INFO "(rcpci45 driver:) RC GETPROM\n"); - RCUD_GETPROM = &RCuser.RCUS_GETPROM; - RCGetPromiscuousMode(dev, (PU32) &RCUD_GETPROM->PromMode, NULL); - break; - case RCUC_GETBROADCAST: - printk(KERN_INFO "(rcpci45 driver:) RC GETBROADCAST\n"); - RCUD_GETBROADCAST = &RCuser.RCUS_GETBROADCAST; - RCGetBroadcastMode(dev, (PU32) &RCUD_GETBROADCAST->BroadcastMode, NULL); - break; - case RCUC_GETSPEED: - printk(KERN_INFO "(rcpci45 driver:) RC GETSPEED\n"); - if (!(dev->flags & IFF_UP)) - { - printk(KERN_ERR "(rcpci45 driver:) RCioctl, GETSPEED error: interface down\n"); - return -ENODATA; - } - RCUD_GETSPEED = &RCuser.RCUS_GETSPEED; - RCGetLinkSpeed(dev, (PU32) &RCUD_GETSPEED->LinkSpeedCode, NULL); - printk(KERN_INFO "(rcpci45 driver:) RC speed = 0x%u\n", RCUD_GETSPEED->LinkSpeedCode); - break; - case RCUC_SETIPANDMASK: - printk(KERN_INFO "(rcpci45 driver:) RC SETIPANDMASK\n"); - RCUD_SETIPANDMASK = &RCuser.RCUS_SETIPANDMASK; - printk (KERN_INFO "(rcpci45 driver:) RC New IP Addr = %d.%d.%d.%d, ", (U8) ((RCUD_SETIPANDMASK->IpAddr) & 0xff), - (U8) ((RCUD_SETIPANDMASK->IpAddr >> 8) & 0xff), - (U8) ((RCUD_SETIPANDMASK->IpAddr >> 16) & 0xff), - (U8) ((RCUD_SETIPANDMASK->IpAddr >> 24) & 0xff)); - printk (KERN_INFO "(rcpci45 driver:) RC New Mask = %d.%d.%d.%d\n", (U8) ((RCUD_SETIPANDMASK->NetMask) & 0xff), - (U8) ((RCUD_SETIPANDMASK->NetMask >> 8) & 0xff), - (U8) ((RCUD_SETIPANDMASK->NetMask >> 16) & 0xff), - (U8) ((RCUD_SETIPANDMASK->NetMask >> 24) & 0xff)); - RCSetRavlinIPandMask(dev, (U32) RCUD_SETIPANDMASK->IpAddr, - (U32) RCUD_SETIPANDMASK->NetMask); - break; - case RCUC_SETMAC: - printk(KERN_INFO "(rcpci45 driver:) RC SETMAC\n"); - RCUD_SETMAC = &RCuser.RCUS_SETMAC; - printk (KERN_INFO "(rcpci45 driver:) RC New MAC addr = %02X:%02X:%02X:%02X:%02X:%02X\n", - (U8) (RCUD_SETMAC->mac[0]), (U8) (RCUD_SETMAC->mac[1]), (U8) (RCUD_SETMAC->mac[2]), - (U8) (RCUD_SETMAC->mac[3]), (U8) (RCUD_SETMAC->mac[4]), (U8) (RCUD_SETMAC->mac[5])); - RCSetMAC(dev, (PU8) &RCUD_SETMAC->mac); - break; - case RCUC_SETSPEED: - printk(KERN_INFO "(rcpci45 driver:) RC SETSPEED\n"); - RCUD_SETSPEED = &RCuser.RCUS_SETSPEED; - RCSetLinkSpeed(dev, (U16) RCUD_SETSPEED->LinkSpeedCode); - printk(KERN_INFO "(rcpci45 driver:) RC New speed = 0x%x\n", RCUD_SETSPEED->LinkSpeedCode); - break; - case RCUC_SETPROM: - printk(KERN_INFO "(rcpci45 driver:) RC SETPROM\n"); - RCUD_SETPROM = &RCuser.RCUS_SETPROM; - RCSetPromiscuousMode(dev,(U16)RCUD_SETPROM->PromMode); - printk(KERN_INFO "(rcpci45 driver:) RC New prom mode = 0x%x\n", RCUD_SETPROM->PromMode); - break; - case RCUC_SETBROADCAST: - printk(KERN_INFO "(rcpci45 driver:) RC SETBROADCAST\n"); - RCUD_SETBROADCAST = &RCuser.RCUS_SETBROADCAST; - RCSetBroadcastMode(dev,(U16)RCUD_SETBROADCAST->BroadcastMode); - printk(KERN_INFO "(rcpci45 driver:) RC New broadcast mode = 0x%x\n", RCUD_SETBROADCAST->BroadcastMode); - break; - default: - printk(KERN_INFO "(rcpci45 driver:) RC command default\n"); - RCUD_DEFAULT = &RCuser.RCUS_DEFAULT; - RCUD_DEFAULT -> rc = 0x11223344; - break; - } - if(copy_to_user(rq->ifr_data, &RCuser, sizeof(RCuser))) - return -EFAULT; - break; - } /* RCU_COMMAND */ + RCuser_struct RCuser; + PDPA pDpa = dev->priv; + + dprintk ("RCioctl: cmd = 0x%x\n", cmd); + + if (!capable (CAP_NET_ADMIN)) + return -EPERM; + + switch (cmd) { + + case RCU_PROTOCOL_REV: + /* + * Assign user protocol revision, to tell user-level + * controller program whether or not it's in sync. + */ + rq->ifr_ifru.ifru_data = (caddr_t) USER_PROTOCOL_REV; + break; + + case RCU_COMMAND: + { + if (copy_from_user + (&RCuser, rq->ifr_data, sizeof (RCuser))) + return -EFAULT; + + dprintk ("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd); + + switch (RCuser.cmd) { + case RCUC_GETFWVER: + printk (KERN_INFO + "(rcpci45 driver:) RC GETFWVER\n"); + RCUD_GETFWVER = &RCuser.RCUS_GETFWVER; + RCGetFirmwareVer (dev, + (PU8) & RCUD_GETFWVER-> + FirmString, NULL); + break; + case RCUC_GETINFO: + printk (KERN_INFO + "(rcpci45 driver:) RC GETINFO\n"); + RCUD_GETINFO = &RCuser.RCUS_GETINFO; + RCUD_GETINFO->mem_start = dev->base_addr; + RCUD_GETINFO->mem_end = + dev->base_addr + pDpa->pci_addr_len; + RCUD_GETINFO->base_addr = pDpa->pci_addr; + RCUD_GETINFO->irq = dev->irq; + break; + case RCUC_GETIPANDMASK: + printk (KERN_INFO + "(rcpci45 driver:) RC GETIPANDMASK\n"); + RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK; + RCGetRavlinIPandMask (dev, + (PU32) & + RCUD_GETIPANDMASK->IpAddr, + (PU32) & + RCUD_GETIPANDMASK-> + NetMask, NULL); + break; + case RCUC_GETLINKSTATISTICS: + printk (KERN_INFO + "(rcpci45 driver:) RC GETLINKSTATISTICS\n"); + RCUD_GETLINKSTATISTICS = + &RCuser.RCUS_GETLINKSTATISTICS; + RCGetLinkStatistics (dev, + (P_RCLINKSTATS) & + RCUD_GETLINKSTATISTICS-> + StatsReturn, NULL); + break; + case RCUC_GETLINKSTATUS: + printk (KERN_INFO + "(rcpci45 driver:) RC GETLINKSTATUS\n"); + RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS; + RCGetLinkStatus (dev, + (PU32) & RCUD_GETLINKSTATUS-> + ReturnStatus, NULL); + break; + case RCUC_GETMAC: + printk (KERN_INFO + "(rcpci45 driver:) RC GETMAC\n"); + RCUD_GETMAC = &RCuser.RCUS_GETMAC; + RCGetMAC (dev, NULL); + break; + case RCUC_GETPROM: + printk (KERN_INFO + "(rcpci45 driver:) RC GETPROM\n"); + RCUD_GETPROM = &RCuser.RCUS_GETPROM; + RCGetPromiscuousMode (dev, + (PU32) & RCUD_GETPROM-> + PromMode, NULL); + break; + case RCUC_GETBROADCAST: + printk (KERN_INFO + "(rcpci45 driver:) RC GETBROADCAST\n"); + RCUD_GETBROADCAST = &RCuser.RCUS_GETBROADCAST; + RCGetBroadcastMode (dev, + (PU32) & RCUD_GETBROADCAST-> + BroadcastMode, NULL); + break; + case RCUC_GETSPEED: + printk (KERN_INFO + "(rcpci45 driver:) RC GETSPEED\n"); + if (!(dev->flags & IFF_UP)) { + printk (KERN_ERR + "(rcpci45 driver:) RCioctl, GETSPEED error: interface down\n"); + return -ENODATA; + } + RCUD_GETSPEED = &RCuser.RCUS_GETSPEED; + RCGetLinkSpeed (dev, + (PU32) & RCUD_GETSPEED-> + LinkSpeedCode, NULL); + printk (KERN_INFO + "(rcpci45 driver:) RC speed = 0x%u\n", + RCUD_GETSPEED->LinkSpeedCode); + break; + case RCUC_SETIPANDMASK: + printk (KERN_INFO + "(rcpci45 driver:) RC SETIPANDMASK\n"); + RCUD_SETIPANDMASK = &RCuser.RCUS_SETIPANDMASK; + printk (KERN_INFO + "(rcpci45 driver:) RC New IP Addr = %d.%d.%d.%d, ", + (U8) ((RCUD_SETIPANDMASK-> + IpAddr) & 0xff), + (U8) ((RCUD_SETIPANDMASK-> + IpAddr >> 8) & 0xff), + (U8) ((RCUD_SETIPANDMASK-> + IpAddr >> 16) & 0xff), + (U8) ((RCUD_SETIPANDMASK-> + IpAddr >> 24) & 0xff)); + printk (KERN_INFO + "(rcpci45 driver:) RC New Mask = %d.%d.%d.%d\n", + (U8) ((RCUD_SETIPANDMASK-> + NetMask) & 0xff), + (U8) ((RCUD_SETIPANDMASK-> + NetMask >> 8) & 0xff), + (U8) ((RCUD_SETIPANDMASK-> + NetMask >> 16) & 0xff), + (U8) ((RCUD_SETIPANDMASK-> + NetMask >> 24) & 0xff)); + RCSetRavlinIPandMask (dev, + (U32) RCUD_SETIPANDMASK-> + IpAddr, + (U32) RCUD_SETIPANDMASK-> + NetMask); + break; + case RCUC_SETMAC: + printk (KERN_INFO + "(rcpci45 driver:) RC SETMAC\n"); + RCUD_SETMAC = &RCuser.RCUS_SETMAC; + printk (KERN_INFO + "(rcpci45 driver:) RC New MAC addr = %02X:%02X:%02X:%02X:%02X:%02X\n", + (U8) (RCUD_SETMAC->mac[0]), + (U8) (RCUD_SETMAC->mac[1]), + (U8) (RCUD_SETMAC->mac[2]), + (U8) (RCUD_SETMAC->mac[3]), + (U8) (RCUD_SETMAC->mac[4]), + (U8) (RCUD_SETMAC->mac[5])); + RCSetMAC (dev, (PU8) & RCUD_SETMAC->mac); + break; + case RCUC_SETSPEED: + printk (KERN_INFO + "(rcpci45 driver:) RC SETSPEED\n"); + RCUD_SETSPEED = &RCuser.RCUS_SETSPEED; + RCSetLinkSpeed (dev, + (U16) RCUD_SETSPEED-> + LinkSpeedCode); + printk (KERN_INFO + "(rcpci45 driver:) RC New speed = 0x%x\n", + RCUD_SETSPEED->LinkSpeedCode); + break; + case RCUC_SETPROM: + printk (KERN_INFO + "(rcpci45 driver:) RC SETPROM\n"); + RCUD_SETPROM = &RCuser.RCUS_SETPROM; + RCSetPromiscuousMode (dev, + (U16) RCUD_SETPROM-> + PromMode); + printk (KERN_INFO + "(rcpci45 driver:) RC New prom mode = 0x%x\n", + RCUD_SETPROM->PromMode); + break; + case RCUC_SETBROADCAST: + printk (KERN_INFO + "(rcpci45 driver:) RC SETBROADCAST\n"); + RCUD_SETBROADCAST = &RCuser.RCUS_SETBROADCAST; + RCSetBroadcastMode (dev, + (U16) RCUD_SETBROADCAST-> + BroadcastMode); + printk (KERN_INFO + "(rcpci45 driver:) RC New broadcast mode = 0x%x\n", + RCUD_SETBROADCAST->BroadcastMode); + break; + default: + printk (KERN_INFO + "(rcpci45 driver:) RC command default\n"); + RCUD_DEFAULT = &RCuser.RCUS_DEFAULT; + RCUD_DEFAULT->rc = 0x11223344; + break; + } + if (copy_to_user + (rq->ifr_data, &RCuser, sizeof (RCuser))) + return -EFAULT; + break; + } /* RCU_COMMAND */ default: - rq->ifr_ifru.ifru_data = (caddr_t) 0x12345678; - return -EINVAL; - } - return 0; + rq->ifr_ifru.ifru_data = (caddr_t) 0x12345678; + return -EINVAL; + } + return 0; } -static int RCconfig(struct net_device *dev, struct ifmap *map) +static int +RCconfig (struct net_device *dev, struct ifmap *map) { - /* - * To be completed ... - */ - dprintk("RCconfig\n"); - return 0; - if (dev->flags & IFF_UP) /* can't act on a running interface */ - return -EBUSY; - - /* Don't allow changing the I/O address */ - if (map->base_addr != dev->base_addr) { - printk(KERN_WARNING "(rcpci45 driver:) Change I/O address not implemented\n"); - return -EOPNOTSUPP; - } - return 0; + /* + * To be completed ... + */ + dprintk ("RCconfig\n"); + return 0; + if (dev->flags & IFF_UP) /* can't act on a running interface */ + return -EBUSY; + + /* Don't allow changing the I/O address */ + if (map->base_addr != dev->base_addr) { + printk (KERN_WARNING + "(rcpci45 driver:) Change I/O address not implemented\n"); + return -EOPNOTSUPP; + } + return 0; } - -static void __exit rcpci_cleanup_module (void) +static void __exit +rcpci_cleanup_module (void) { - pci_unregister_driver(&rcpci45_driver); + pci_unregister_driver (&rcpci45_driver); } -module_init(rcpci_init_module); -module_exit(rcpci_cleanup_module); - +module_init (rcpci_init_module); +module_exit (rcpci_cleanup_module); static int -RC_allocate_and_post_buffers(struct net_device *dev, int numBuffers) +RC_allocate_and_post_buffers (struct net_device *dev, int numBuffers) { - int i; - PU32 p; - psingleB pB; - struct sk_buff *skb; - RC_RETURN status; - U32 res; - - if (!numBuffers) - return 0; - else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG) - { - dprintk("Too many buffers requested!\n"); - dprintk("attempting to allocate only 32 buffers\n"); - numBuffers = 32; - } - - p = (PU32) kmalloc(sizeof(U32) + numBuffers*sizeof(singleB), GFP_KERNEL); - - dprintk("TCB = 0x%x\n", (uint)p); - - if (!p) - { - printk(KERN_WARNING "(rcpci45 driver:) RCopen: unable to allocate TCB\n"); - return 0; - } - - p[0] = 0; /* Buffer Count */ - pB = (psingleB)((U32)p + sizeof(U32)); /* point to the first buffer */ - - dprintk("p[0] = 0x%x, p = 0x%x, pB = 0x%x\n", (uint)p[0], (uint)p, (uint)pB); - dprintk("pB = 0x%x\n", (uint)pB); - - for (i=0; i<numBuffers; i++) - { - skb = dev_alloc_skb(MAX_ETHER_SIZE+2); - if (!skb) - { - dprintk("Doh! RCopen: unable to allocate enough skbs!\n"); - if (*p != 0) /* did we allocate any buffers at all? */ - { - dprintk("will post only %d buffers \n", (uint)(*p)); - break; - } - else - { - kfree(p); /* Free the TCB */ - return 0; - } - } - dprintk("post 0x%x\n", (uint)skb); - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - pB->context = (U32)skb; - pB->scount = 1; /* segment count */ - pB->size = MAX_ETHER_SIZE; - pB->addr = virt_to_bus((void *)skb->data); - p[0]++; - pB++; - } - - if ( (status = RCPostRecvBuffers(dev, (PRCTCB)p )) != RC_RTN_NO_ERROR) - { - printk(KERN_WARNING "(rcpci45 driver:) Post buffer failed with error code 0x%x!\n", status); - pB = (psingleB)((U32)p + sizeof(U32)); /* point to the first buffer */ - while(p[0]) - { - skb = (struct sk_buff *)pB->context; - dprintk("freeing 0x%x\n", (uint)skb); - dev_kfree_skb (skb); - p[0]--; - pB++; - } - dprintk("freed all buffers, p[0] = %d\n", (uint)p[0]); - } - res = p[0]; - kfree(p); - return(res); /* return the number of posted buffers */ + int i; + PU32 p; + psingleB pB; + struct sk_buff *skb; + RC_RETURN status; + U32 res; + + if (!numBuffers) + return 0; + else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG) { + dprintk ("Too many buffers requested!\n"); + dprintk ("attempting to allocate only 32 buffers\n"); + numBuffers = 32; + } + + p = (PU32) kmalloc (sizeof (U32) + numBuffers * sizeof (singleB), + GFP_KERNEL); + + dprintk ("TCB = 0x%x\n", (uint) p); + + if (!p) { + printk (KERN_WARNING + "(rcpci45 driver:) RCopen: unable to allocate TCB\n"); + return 0; + } + + p[0] = 0; /* Buffer Count */ + pB = (psingleB) ((U32) p + sizeof (U32)); /* point to the first buffer */ + + dprintk ("p[0] = 0x%x, p = 0x%x, pB = 0x%x\n", (uint) p[0], (uint) p, + (uint) pB); + dprintk ("pB = 0x%x\n", (uint) pB); + + for (i = 0; i < numBuffers; i++) { + skb = dev_alloc_skb (MAX_ETHER_SIZE + 2); + if (!skb) { + dprintk + ("Doh! RCopen: unable to allocate enough skbs!\n"); + if (*p != 0) { /* did we allocate any buffers at all? */ + dprintk ("will post only %d buffers \n", + (uint) (*p)); + break; + } else { + kfree (p); /* Free the TCB */ + return 0; + } + } + dprintk ("post 0x%x\n", (uint) skb); + skb_reserve (skb, 2); /* Align IP on 16 byte boundaries */ + pB->context = (U32) skb; + pB->scount = 1; /* segment count */ + pB->size = MAX_ETHER_SIZE; + pB->addr = virt_to_bus ((void *) skb->data); + p[0]++; + pB++; + } + + if ((status = RCPostRecvBuffers (dev, (PRCTCB) p)) != RC_RTN_NO_ERROR) { + printk (KERN_WARNING + "(rcpci45 driver:) Post buffer failed with error code 0x%x!\n", + status); + pB = (psingleB) ((U32) p + sizeof (U32)); /* point to the first buffer */ + while (p[0]) { + skb = (struct sk_buff *) pB->context; + dprintk ("freeing 0x%x\n", (uint) skb); + dev_kfree_skb (skb); + p[0]--; + pB++; + } + dprintk ("freed all buffers, p[0] = %d\n", (uint) p[0]); + } + res = p[0]; + kfree (p); + return (res); /* return the number of posted buffers */ } diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c index 27f33848aece..bf6dcec69820 100644 --- a/drivers/net/saa9730.c +++ b/drivers/net/saa9730.c @@ -44,7 +44,7 @@ int lan_saa9730_debug; /* Non-zero only if the current card is a PCI with BIOS-set IRQ. */ -static unsigned int pci_irq_line = 0; +static unsigned int pci_irq_line; #define INL(a) inl((unsigned long)a) #define OUTL(x,a) outl(x,(unsigned long)a) diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 3fb384b1116d..120fceac71f9 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -53,6 +53,7 @@ #include <linux/pci.h> #include <linux/netdevice.h> #include <linux/init.h> +#include <linux/mii.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> @@ -1702,19 +1703,24 @@ sis900_close(struct net_device *net_dev) static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) { struct sis900_private *sis_priv = net_dev->priv; - u16 *data = (u16 *)&rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = sis_priv->mii->phy_addr; + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = sis_priv->mii->phy_addr; /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(net_dev, data[0] & 0x1f, data[1] & 0x1f); + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + data->val_out = mdio_read(net_dev, data->phy_id & 0x1f, data->reg_num & 0x1f); return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - mdio_write(net_dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(net_dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); return 0; default: return -EOPNOTSUPP; diff --git a/drivers/net/sis900.h b/drivers/net/sis900.h index 4c31cfccc023..b3ddbcca6885 100644 --- a/drivers/net/sis900.h +++ b/drivers/net/sis900.h @@ -266,13 +266,5 @@ enum sis630_revision_id { #define NUM_TX_DESC 16 /* Number of Tx descriptor registers. */ #define NUM_RX_DESC 16 /* Number of Rx descriptor registers. */ -/* PCI stuff, should be move to pic.h */ -#define PCI_DEVICE_ID_SI_900 0x900 -#define PCI_DEVICE_ID_SI_7016 0x7016 #define SIS630_VENDOR_ID 0x1039 #define SIS630_DEVICE_ID 0x0630 - -/* ioctl for accessing MII transceiver */ -#define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Get the PHY in use. */ -#define SIOCGMIIREG (SIOCDEVPRIVATE+1) /* Read a PHY register. */ -#define SIOCSMIIREG (SIOCDEVPRIVATE+2) /* Write a PHY register */ diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c index ff893e3e0a5b..ebf9902f4e65 100644 --- a/drivers/net/sk_g16.c +++ b/drivers/net/sk_g16.c @@ -536,8 +536,6 @@ void SK_print_ram(struct net_device *dev); * Check for a network adaptor of this type, and return '0' if one exists. * If dev->base_addr == 0, probe all likely locations. * If dev->base_addr == 1, always return failure. - * If dev->base_addr == 2, allocate space for the device and return success - * (detachable devices only). */ int __init SK_init(struct net_device *dev) diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 30d0c2a23fcd..5e52cc461856 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -149,7 +149,7 @@ static int multicast_filter_limit = 512; #if defined(__ia64__) || defined(__alpha__) || defined(__sparc__) static int rx_copybreak = PKT_BUF_SZ; #else -static int rx_copybreak = 0; +static int rx_copybreak /* = 0 */; #endif /* Used to pass the media type, etc. @@ -585,7 +585,7 @@ static int netdev_rx(struct net_device *dev); static void netdev_error(struct net_device *dev, int intr_status); static void set_rx_mode(struct net_device *dev); static struct net_device_stats *get_stats(struct net_device *dev); -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_close(struct net_device *dev); static void netdev_media_change(struct net_device *dev); @@ -726,7 +726,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, dev->stop = &netdev_close; dev->get_stats = &get_stats; dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &mii_ioctl; + dev->do_ioctl = &netdev_ioctl; if (mtu) dev->mtu = mtu; @@ -1664,38 +1664,149 @@ static void set_rx_mode(struct net_device *dev) *fptr |= cpu_to_le32(1 << (bit_nr & 31)); } - /* Clear the perfect filter list. */ - filter_addr = ioaddr + 0x56000 + 1*16; + /* Clear the perfect filter list, skip first entry. */ + filter_addr = ioaddr + PerfFilterTable + 1 * 16; for (i = 1; i < 16; i++) { writew(0xffff, filter_addr); filter_addr += 4; writew(0xffff, filter_addr); filter_addr += 4; writew(0xffff, filter_addr); filter_addr += 8; } - for (filter_addr=ioaddr + 0x56100, i=0; i < 32; filter_addr+= 16, i++) + for (filter_addr = ioaddr + HashTable, i=0; i < 32; filter_addr+= 16, i++) writew(mc_filter[i], filter_addr); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; } writel(rx_mode, ioaddr + RxFilterMode); } -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) + + +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct ethtool_cmd ecmd; + struct netdev_private *np = dev->priv; + + if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) + return -EFAULT; + + switch (ecmd.cmd) { + case ETHTOOL_GSET: + ecmd.supported = + SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_MII; + + ecmd.advertising = ADVERTISED_MII; + if (np->advertising & ADVERTISE_10HALF) + ecmd.advertising |= ADVERTISED_10baseT_Half; + if (np->advertising & ADVERTISE_10FULL) + ecmd.advertising |= ADVERTISED_10baseT_Full; + if (np->advertising & ADVERTISE_100HALF) + ecmd.advertising |= ADVERTISED_100baseT_Half; + if (np->advertising & ADVERTISE_100FULL) + ecmd.advertising |= ADVERTISED_100baseT_Full; + if (np->autoneg) { + ecmd.advertising |= ADVERTISED_Autoneg; + ecmd.autoneg = AUTONEG_ENABLE; + } else + ecmd.autoneg = AUTONEG_DISABLE; + + ecmd.port = PORT_MII; + ecmd.transceiver = XCVR_INTERNAL; + ecmd.phy_address = np->phys[0]; + ecmd.speed = np->speed100 ? SPEED_100 : SPEED_10; + ecmd.duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; + ecmd.maxtxpkt = TX_RING_SIZE; + ecmd.maxrxpkt = np->intr_mitigation; /* not 100% accurate */ + + + if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + + case ETHTOOL_SSET: { + u16 autoneg, speed100, full_duplex; + + autoneg = (ecmd.autoneg == AUTONEG_ENABLE); + speed100 = (ecmd.speed == SPEED_100); + full_duplex = (ecmd.duplex == DUPLEX_FULL); + + np->autoneg = autoneg; + if (speed100 != np->speed100 || + full_duplex != np->full_duplex) { + np->speed100 = speed100; + np->full_duplex = full_duplex; + /* change advertising bits */ + np->advertising &= ~(ADVERTISE_10HALF | + ADVERTISE_10FULL | + ADVERTISE_100HALF | + ADVERTISE_100FULL | + ADVERTISE_100BASE4); + if (speed100) { + if (full_duplex) + np->advertising |= ADVERTISE_100FULL; + else + np->advertising |= ADVERTISE_100HALF; + } else { + if (full_duplex) + np->advertising |= ADVERTISE_10FULL; + else + np->advertising |= ADVERTISE_10HALF; + } + } + check_duplex(dev); + return 0; + } + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info; + memset(&info, 0, sizeof(info)); + info.cmd = ecmd.cmd; + strcpy(info.driver, DRV_NAME); + strcpy(info.version, DRV_VERSION); + *info.fw_version = 0; + strcpy(info.bus_info, PCI_SLOT_NAME(np->pci_dev)); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + + default: + return -EOPNOTSUPP; + } +} + + + +static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct netdev_private *np = dev->priv; - u16 *data = (u16 *)&rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = np->phys[0] & 0x1f; + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + + /* Legacy mii-diag interface */ + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = np->phys[0] & 0x1f; /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (data[0] == np->phys[0]) { - u16 value = data[2]; - switch (data[1]) { + if (data->phy_id == np->phys[0]) { + u16 value = data->val_in; + switch (data->reg_num) { case 0: if (value & 0x9000) /* Autonegotiation. */ np->autoneg = 1; @@ -1710,7 +1821,7 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } check_duplex(dev); } - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); return 0; default: return -EOPNOTSUPP; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 57fed91b5ae0..f991214819c9 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -91,6 +91,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; #include <linux/skbuff.h> #include <linux/init.h> #include <linux/ethtool.h> +#include <linux/mii.h> #include <asm/uaccess.h> #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/bitops.h> @@ -1195,21 +1196,26 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - u16 *data = (u16 *)&rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; switch(cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f; + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f; /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); return 0; default: return -EOPNOTSUPP; diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 649ea3688954..dbba4a020fb9 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -171,6 +171,7 @@ #include <linux/etherdevice.h> #include <linux/delay.h> #include <linux/spinlock.h> +#include <linux/mii.h> typedef u32 (TLanIntVectorFunc)( struct net_device *, u16 ); @@ -245,21 +246,21 @@ static struct board { }; static struct pci_device_id tlan_pci_tbl[] __devinitdata = { - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETFLEX3I, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_THUNDER, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P_BNC, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETFLEX3B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100PI, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_DESKPRO_4000_5233MMX, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100I, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2183, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, @@ -911,24 +912,29 @@ static int TLan_Open( struct net_device *dev ) static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { TLanPrivateInfo *priv = dev->priv; - u16 *data = (u16 *)&rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; u32 phy = priv->phy[priv->phyNum]; if (!priv->phyOnline) return -EAGAIN; switch(cmd) { - case SIOCDEVPRIVATE: - data[0] = phy; + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = phy; - case SIOCDEVPRIVATE+1: /* Read MII register */ - TLan_MiiReadReg(dev, data[0] & 0x1f, data[1] & 0x1f, &data[3]); + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + TLan_MiiReadReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, &data->val_out); return 0; - case SIOCDEVPRIVATE+2: /* Write MII register */ + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - TLan_MiiWriteReg(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + TLan_MiiWriteReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); return 0; default: return -EOPNOTSUPP; diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h index 09fee7a20266..fb51f45c1b2d 100644 --- a/drivers/net/tlan.h +++ b/drivers/net/tlan.h @@ -61,14 +61,6 @@ * ****************************************************************/ -#define PCI_DEVICE_ID_NETELLIGENT_10 0xAE34 -#define PCI_DEVICE_ID_NETELLIGENT_10_100 0xAE32 -#define PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED 0xAE35 -#define PCI_DEVICE_ID_NETFLEX_3P 0xF130 -#define PCI_DEVICE_ID_NETFLEX_3P_BNC 0xF150 -#define PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT 0xAE43 -#define PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL 0xAE40 -#define PCI_DEVICE_ID_DESKPRO_4000_5233MMX 0xB011 #define PCI_DEVICE_ID_NETELLIGENT_10_T2 0xB012 #define PCI_DEVICE_ID_NETELLIGENT_10_100_WS_5100 0xB030 #ifndef PCI_DEVICE_ID_OLICOM_OC2183 diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index bdef3c78dd32..6488b2af7125 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -15,8 +15,8 @@ */ #define DRV_NAME "tulip" -#define DRV_VERSION "0.9.15-pre5" -#define DRV_RELDATE "June 16, 2001" +#define DRV_VERSION "0.9.15-pre6" +#define DRV_RELDATE "July 2, 2001" #include <linux/config.h> #include <linux/module.h> @@ -924,66 +924,72 @@ static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { struct tulip_private *tp = dev->priv; long ioaddr = dev->base_addr; - u16 *data = (u16 *) & rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; const unsigned int phy_idx = 0; int phy = tp->phys[phy_idx] & 0x1f; - unsigned int regnum = data[1]; + unsigned int regnum = data->reg_num; switch (cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ if (tp->mii_cnt) - data[0] = phy; + data->phy_id = phy; else if (tp->flags & HAS_NWAY) - data[0] = 32; + data->phy_id = 32; else if (tp->chip_id == COMET) - data[0] = 1; + data->phy_id = 1; else return -ENODEV; - case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */ - if (data[0] == 32 && (tp->flags & HAS_NWAY)) { + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + if (data->phy_id == 32 && (tp->flags & HAS_NWAY)) { int csr12 = inl (ioaddr + CSR12); int csr14 = inl (ioaddr + CSR14); switch (regnum) { case 0: if (((csr14<<5) & 0x1000) || (dev->if_port == 5 && tp->nwayset)) - data[3] = 0x1000; + data->val_out = 0x1000; else - data[3] = (tulip_media_cap[dev->if_port]&MediaIs100 ? 0x2000 : 0) + data->val_out = (tulip_media_cap[dev->if_port]&MediaIs100 ? 0x2000 : 0) | (tulip_media_cap[dev->if_port]&MediaIsFD ? 0x0100 : 0); break; case 1: - data[3] = + data->val_out = 0x1848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0) + ((csr12&0x06) == 6 ? 0 : 4); if (tp->chip_id != DC21041) - data[3] |= 0x6048; + data->val_out |= 0x6048; break; case 4: /* Advertised value, bogus 10baseTx-FD value from CSR6. */ - data[3] = + data->val_out = ((inl(ioaddr + CSR6) >> 3) & 0x0040) + ((csr14 >> 1) & 0x20) + 1; if (tp->chip_id != DC21041) - data[3] |= ((csr14 >> 9) & 0x03C0); + data->val_out |= ((csr14 >> 9) & 0x03C0); break; - case 5: data[3] = tp->lpar; break; - default: data[3] = 0; break; + case 5: data->val_out = tp->lpar; break; + default: data->val_out = 0; break; } } else { - data[3] = tulip_mdio_read (dev, data[0] & 0x1f, regnum); + data->val_out = tulip_mdio_read (dev, data->phy_id & 0x1f, regnum); } return 0; - case SIOCDEVPRIVATE + 2: /* Write the specified MII register */ + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable (CAP_NET_ADMIN)) return -EPERM; if (regnum & ~0x1f) return -EINVAL; - if (data[0] == phy) { - u16 value = data[2]; + if (data->phy_id == phy) { + u16 value = data->val_in; switch (regnum) { case 0: /* Check for autonegotiation on or reset. */ tp->full_duplex_lock = (value & 0x9000) ? 0 : 1; @@ -992,19 +998,19 @@ static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) break; case 4: tp->advertising[phy_idx] = - tp->mii_advertise = data[2]; + tp->mii_advertise = data->val_in; break; } } - if (data[0] == 32 && (tp->flags & HAS_NWAY)) { - u16 value = data[2]; + if (data->phy_id == 32 && (tp->flags & HAS_NWAY)) { + u16 value = data->val_in; if (regnum == 0) { if ((value & 0x1200) == 0x1200) t21142_start_nway (dev); } else if (regnum == 4) tp->sym_advertise = value; } else { - tulip_mdio_write (dev, data[0] & 0x1f, regnum, data[2]); + tulip_mdio_write (dev, data->phy_id & 0x1f, regnum, data->val_in); } return 0; default: diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 6cf307489b7e..267029865e51 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -139,6 +139,7 @@ static const int multicast_filter_limit = 32; #include <linux/skbuff.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/mii.h> #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/bitops.h> #include <asm/io.h> @@ -1485,7 +1486,7 @@ static void via_rhine_set_rx_mode(struct net_device *dev) static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct netdev_private *np = dev->priv; - u16 *data = (u16 *)&rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; unsigned long flags; int retval; @@ -1493,18 +1494,23 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) retval = 0; switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = np->phys[0] & 0x1f; + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = np->phys[0] & 0x1f; /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); break; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) { retval = -EPERM; break; } - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); break; default: retval = -EOPNOTSUPP; diff --git a/drivers/net/wavelan.p.h b/drivers/net/wavelan.p.h index 749b7039b5cb..64b2d5c3ea1c 100644 --- a/drivers/net/wavelan.p.h +++ b/drivers/net/wavelan.p.h @@ -699,12 +699,15 @@ static unsigned short iobase[] = #ifdef MODULE /* Parameters set by insmod */ -static int io[4] = { 0, 0, 0, 0 }; -static int irq[4] = { 0, 0, 0, 0 }; -static char name[4][IFNAMSIZ] = { "", "", "", "" }; +static int io[4]; +static int irq[4]; +static char name[4][IFNAMSIZ]; MODULE_PARM(io, "1-4i"); MODULE_PARM(irq, "1-4i"); MODULE_PARM(name, "1-4c" __MODULE_STRING(IFNAMSIZ)); +MODULE_PARM_DESC(io, "WaveLAN I/O base address(es),required"); +MODULE_PARM_DESC(irq, "WaveLAN IRQ number(s)"); +MODULE_PARM_DESC(name, "WaveLAN interface neme(s)"); #endif /* MODULE */ #endif /* WAVELAN_P_H */ diff --git a/drivers/net/winbond-840.c b/drivers/net/winbond-840.c index ab30926e6f2d..cc190b6aa45a 100644 --- a/drivers/net/winbond-840.c +++ b/drivers/net/winbond-840.c @@ -128,6 +128,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; #include <linux/init.h> #include <linux/delay.h> #include <linux/ethtool.h> +#include <linux/mii.h> #include <asm/uaccess.h> #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/bitops.h> @@ -1349,21 +1350,26 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - u16 *data = (u16 *)&rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; switch(cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f; + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f; /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); return 0; default: return -EOPNOTSUPP; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index c7426d35aaf2..9ec5678450f8 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2984,14 +2984,9 @@ static int __init airo_init_module( void ) printk( KERN_INFO "airo: Finished probing for PCI adapters\n" ); #endif - /* arguably, we should clean up and error exit if pci_module_init - * fails with an error other than -ENODEV, instead of proceeding, - * if ISA devs are present. + /* Always exit with success, as we are a library module + * as well as a driver module */ - if (have_isa_dev) - return 0; - if (rc && (rc != -ENODEV)) - return rc; return 0; } diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index d2b5d949fca0..8bf94dc46acd 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -108,8 +108,8 @@ static dev_info_t dev_info = "orinoco_cs"; device numbers are used to derive the corresponding array index. */ -static dev_link_t *dev_list = NULL; -static int num_instances = 0; +static dev_link_t *dev_list; +static int num_instances; /*====================================================================*/ diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 3b40f4c65025..c56ce5c266d0 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -1373,23 +1373,28 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct yellowfin_private *np = dev->priv; long ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; switch(cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = np->phys[0] & 0x1f; + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = np->phys[0] & 0x1f; /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f); return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (data[0] == np->phys[0]) { - u16 value = data[2]; - switch (data[1]) { + if (data->phy_id == np->phys[0]) { + u16 value = data->val_in; + switch (data->reg_num) { case 0: /* Check for autonegotiation on or reset. */ np->medialock = (value & 0x9000) ? 0 : 1; @@ -1400,7 +1405,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } /* Perhaps check_duplex(dev), depending on chip semantics. */ } - mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); return 0; default: return -EOPNOTSUPP; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index dd2466224b10..fd7cab0ed056 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -420,11 +420,13 @@ int pci_enable_wake(struct pci_dev *dev, u32 state, int enable) if (!value || !(value & (1 << state))) return enable ? -EINVAL : 0; - /* Enable PME# Generation */ pci_read_config_word(dev, pm + PCI_PM_CTRL, &value); - if (enable) value |= PCI_PM_CTRL_PME_STATUS; - else value &= ~PCI_PM_CTRL_PME_STATUS; + /* Clear PME_Status by writing 1 to it and enable PME# */ + value |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE; + + if (!enable) + value &= ~PCI_PM_CTRL_PME_ENABLE; pci_write_config_word(dev, pm + PCI_PM_CTRL, value); diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids index 1327007b8107..360f4ba122a0 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -244,6 +244,7 @@ 000f OHCI Compliant FireWire Controller 0011 National PCI System I/O 0012 USB Controller + 0020 DP83815 (MacPhyter) Ethernet Controller d001 87410 IDE 100c Tseng Labs Inc 3202 ET4000/W32p rev A @@ -383,10 +384,12 @@ 1014 00cf 16/4 Token-Ring Adapter Special 1014 00e4 High-Speed 100/16/4 Token-Ring Adapter 1014 00e5 16/4 Token-Ring Adapter 2 + Wake-On-LAN + 1014 016d iSeries 2744 Card 0045 SSA Adapter 0046 MPIC interrupt controller 0047 PCI to PCI Bridge 0048 PCI to PCI Bridge + 0049 Warhead SCSI Controller 004e ATM Controller (14104e00) 004f ATM Controller (14104f00) 0050 ATM Controller (14105000) @@ -398,6 +401,10 @@ 0090 GXT 3000P 1014 008E GXT-3000P 0095 20H2999 PCI Docking Bridge + 0096 Chukar chipset SCSI controller + 1014 0099 iSeries 2748 DASD IOA + 1014 0098 iSeries 2763 DASD IOA + 1014 0097 iSeries 2778 DASD IOA 00a5 ATM Controller (1410a500) 00a6 ATM 155MBPS MM Controller (1410a600) 00b7 256-bit Graphics Rasterizer [Fire GL1] @@ -458,6 +465,8 @@ 2040 79c974 7006 AMD-751 [Irongate] System Controller 7007 AMD-751 [Irongate] AGP Bridge + 700E AMD-760 [Irongate] System Controller + 700F AMD-760 [Irongate] AGP Bridge 7400 AMD-755 [Cobra] ISA 7401 AMD-755 [Cobra] IDE 7403 AMD-755 [Cobra] ACPI @@ -466,6 +475,10 @@ 7409 AMD-756 [Viper] IDE 740b AMD-756 [Viper] ACPI 740c AMD-756 [Viper] USB + 7410 AMD-765 [Viper] ISA + 7411 AMD-765 [Viper] IDE + 7413 AMD-765 [Viper] ACPI + 7414 AMD-765 [Viper] USB 1023 Trident Microsystems 0194 82C194 2000 4DWave DX @@ -993,6 +1006,7 @@ 4d30 20267 4d33 20246 4d38 20262 + 4d68 20268 5300 DC5300 105b Foxconn International, Inc. 105c Wipro Infotech Limited @@ -1925,9 +1939,9 @@ 1102 8051 CT4850 SBLive! Value 7002 SB Live! 1102 0020 Gameport Joystick -1103 Triones Technologies, Inc. - 0003 HPT343 - 0004 HPT366 +1103 HighPoint Technologies, Inc. + 0003 HPT343 UltraDMA 33 IDE Controller + 0004 HPT366/370 UltraDMA 66/100 IDE Controller 1104 RasterOps Corp. 1105 Sigma Designs, Inc. 8300 REALmagic Hollywood Plus DVD Decoder @@ -2217,7 +2231,7 @@ 1145 Workbit Corporation 1146 Force Computers 1147 Interface Corp -1148 Syskonnect (Schneider & Koch) +1148 SysKonnect GmbH 4000 FDDI Adapter 0e11 b03b Netelligent 100 FDDI DAS Fibre SC 0e11 b03c Netelligent 100 FDDI SAS Fibre SC @@ -2234,7 +2248,7 @@ 1148 5841 FDDI SK-5841 (SK-NET FDDI-FP64) 1148 5843 FDDI SK-5843 (SK-NET FDDI-LP64) 1148 5844 FDDI SK-5844 (SK-NET FDDI-LP64 DAS) - 4200 Token ring adaptor + 4200 Token Ring adapter 4300 Gigabit Ethernet 1148 9821 SK-9821 (1000Base-T single link) 1148 9822 SK-9822 (1000Base-T dual link) @@ -2242,6 +2256,8 @@ 1148 9842 SK-9842 (1000Base-LX dual link) 1148 9843 SK-9843 (1000Base-SX single link) 1148 9844 SK-9844 (1000Base-SX dual link) + 1148 9861 SK-9861 (1000Base-SX VF45 single link) + 1148 9862 SK-9862 (1000Base-SX VF45 dual link) 1149 Win System Corporation 114a VMIC 7587 VMIVME-7587 @@ -2335,13 +2351,16 @@ 1165 Imagraph Corporation 0001 Motion TPEG Recorder/Player with audio 1166 ServerWorks - 0007 CNB20-LE CPU to PCI Bridge - 0008 CNB20HE - 0009 CNB20LE + 0007 CNB20-LE Host Bridge + 0008 CNB20HE Host Bridge + 0009 CNB20LE Host Bridge 0010 CIOB30 0011 CMIC-HE - 0200 OSB4 - 0201 CSB5 + 0200 OSB4 South Bridge + 0201 CSB5 South Bridge + 0211 OSB4 IDE Controller + 0212 CSB5 IDE Controller + 0220 OSB4/CSB5 OHCI USB Controller 1167 Mutoh Industries Inc 1168 Thine Electronics Inc 1169 Centre for Development of Advanced Computing @@ -2455,7 +2474,9 @@ 1221 82C092G 119c Information Technology Inst. 119d Bug, Inc. Sapporo Japan -119e Fujitsu Microelectronics Ltd. +119e Fujitsu Microelectronics Europe GMBH + 0001 FireStream 155 + 0003 FireStream 50 119f Bull HN Information Systems 11a0 Convex Computer Corporation 11a1 Hamamatsu Photonics K.K. @@ -3002,13 +3023,14 @@ 8086 5643 ES1371, ES1373 AudioPCI On Motherboard Vancouver 8086 5753 ES1371, ES1373 AudioPCI On Motherboard WS440BX 5000 ES1370 [AudioPCI] - 5880 5880 AudioPCI + 4942 4c4c Creative Sound Blaster AudioPCI128 + 5880 CT5880 [AudioPCI] 1274 2000 Creative Sound Blaster AudioPCI128 1274 5880 Creative Sound Blaster AudioPCI128 - 1462 6880 5880 AudioPCI On Motherboard MS-6188 1.00 - 270f 2001 5880 AudioPCI On Motherboard 6CTR - 270f 2200 5880 AudioPCI On Motherboard 6WTX - 270f 7040 5880 AudioPCI On Motherboard 6ATA4 + 1462 6880 CT5880 AudioPCI On Motherboard MS-6188 1.00 + 270f 2001 CT5880 AudioPCI On Motherboard 6CTR + 270f 2200 CT5880 AudioPCI On Motherboard 6WTX + 270f 7040 CT5880 AudioPCI On Motherboard 6ATA4 1275 Network Appliance Corporation 1276 Switched Network Technologies, Inc. 1277 Comstream diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c index b29e90e3cc92..bdf2142b851c 100644 --- a/drivers/scsi/scsi_syms.c +++ b/drivers/scsi/scsi_syms.c @@ -91,3 +91,10 @@ EXPORT_SYMBOL(scsi_hosts); EXPORT_SYMBOL(scsi_devicelist); EXPORT_SYMBOL(scsi_device_types); +/* + * Externalize timers so that HBAs can safely start/restart commands. + */ +extern void scsi_add_timer(Scsi_Cmnd *, int, void ((*) (Scsi_Cmnd *))); +extern int scsi_delete_timer(Scsi_Cmnd *); +EXPORT_SYMBOL(scsi_add_timer); +EXPORT_SYMBOL(scsi_delete_timer); diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index be31c43a3bff..895864901c0a 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -81,6 +81,7 @@ if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then fi dep_tristate ' VIA 82C686 Audio Codec' CONFIG_SOUND_VIA82CXXX $CONFIG_PCI +dep_mbool ' VIA 82C686 MIDI' CONFIG_MIDI_VIA82CXXX $CONFIG_SOUND_VIA82CXXX dep_tristate ' OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index b2ba7941d4ef..8eadb9f97f58 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -47,6 +47,9 @@ obj-$(CONFIG_SOUND_ACI_MIXER) += aci.o obj-$(CONFIG_SOUND_AWE32_SYNTH) += awe_wave.o obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o +ifeq ($(CONFIG_MIDI_VIA82CXXX),y) + obj-$(CONFIG_SOUND_VIA82CXXX) += sound.o uart401.o +endif obj-$(CONFIG_SOUND_YMFPCI) += ymfpci.o ac97_codec.o ifeq ($(CONFIG_SOUND_YMFPCI_LEGACY),y) obj-$(CONFIG_SOUND_YMFPCI) += opl3.o uart401.o diff --git a/drivers/sound/cs4232.c b/drivers/sound/cs4232.c index f32f295c3fa8..d4ff105d211e 100644 --- a/drivers/sound/cs4232.c +++ b/drivers/sound/cs4232.c @@ -42,9 +42,11 @@ * Arnaldo C. de Melo got rid of attach_uart401 * Bartlomiej Zolnierkiewicz * Added some __init/__initdata/__exit + * Marcus Meissner Added ISA PnP support. */ #include <linux/config.h> +#include <linux/isapnp.h> #include <linux/module.h> #include <linux/init.h> @@ -95,7 +97,7 @@ static void sleep(unsigned howlong) schedule_timeout(howlong); } -int __init probe_cs4232(struct address_info *hw_config) +int __init probe_cs4232(struct address_info *hw_config, int isapnp_configured) { int i, n; int base = hw_config->io_base, irq = hw_config->irq; @@ -110,8 +112,13 @@ int __init probe_cs4232(struct address_info *hw_config) printk(KERN_ERR "cs4232.c: I/O port 0x%03x not free\n", base); return 0; } - if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp)) + if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp)) { return 1; /* The card is already active */ + } + if (isapnp_configured) { + printk(KERN_ERR "cs4232.c: ISA PnP configured, but not detected?\n"); + return 0; + } /* * This version of the driver doesn't use the PnP method when configuring @@ -318,27 +325,97 @@ static int __initdata mpuio = -1; static int __initdata mpuirq = -1; static int __initdata synthio = -1; static int __initdata synthirq = -1; +static int __initdata isapnp = 1; - +MODULE_DESCRIPTION("CS4232 based soundcard driver"); +MODULE_AUTHOR("Hannu Savolainen, Paul Barton-Davis"); MODULE_PARM(io,"i"); +MODULE_PARM_DESC(io,"base I/O port for AD1848"); MODULE_PARM(irq,"i"); +MODULE_PARM_DESC(irq,"IRQ for AD1848 chip"); MODULE_PARM(dma,"i"); +MODULE_PARM_DESC(dma,"8 bit DMA for AD1848 chip"); MODULE_PARM(dma2,"i"); +MODULE_PARM_DESC(dma2,"16 bit DMA for AD1848 chip"); MODULE_PARM(mpuio,"i"); +MODULE_PARM_DESC(mpuio,"MPU 401 base address"); MODULE_PARM(mpuirq,"i"); +MODULE_PARM_DESC(mpuirq,"MPU 401 IRQ"); MODULE_PARM(synthio,"i"); +MODULE_PARM_DESC(synthio,"Maui WaveTable base I/O port"); MODULE_PARM(synthirq,"i"); +MODULE_PARM_DESC(synthirq,"Maui WaveTable IRQ"); +MODULE_PARM(isapnp,"i"); +MODULE_PARM_DESC(isapnp,"Enable ISAPnP probing (default 1)"); /* * Install a CS4232 based card. Need to have ad1848 and mpu401 * loaded ready. */ +/* All cs4232 based cards have the main ad1848 card either as CSC0000 or + * CSC0100. */ +struct isapnp_device_id isapnp_cs4232_list[] __initdata = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('C','S','C'), ISAPNP_FUNCTION(0x0100), + 0 }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('C','S','C'), ISAPNP_FUNCTION(0x0000), + 0 }, + /* Guillemot Turtlebeach something appears to be cs4232 compatible + * (untested) */ + { ISAPNP_VENDOR('C','S','C'), ISAPNP_ANY_ID, + ISAPNP_VENDOR('G','I','M'), ISAPNP_FUNCTION(0x0100), + 0 }, + {0} +}; + +MODULE_DEVICE_TABLE(isapnp, isapnp_cs4232_list); + +int cs4232_isapnp_probe(struct pci_dev *dev, const struct isapnp_device_id *id) +{ + int ret; + struct address_info *isapnpcfg; + + isapnpcfg=(struct address_info*)kmalloc(sizeof(*isapnpcfg),GFP_KERNEL); + if (!isapnpcfg) + return -ENOMEM; + /* + * If device is active, assume configured with /proc/isapnp + * and use anyway. Any other way to check this? + */ + ret = dev->prepare(dev); + if(ret && ret != -EBUSY) { + printk(KERN_ERR "cs4232: ISA PnP found device that could not be autoconfigured.\n"); + kfree(isapnpcfg); + return -ENODEV; + } + if(ret != -EBUSY) { + if(dev->activate(dev) < 0) { + printk(KERN_WARNING "cs4232: ISA PnP activate failed\n"); + kfree(isapnpcfg); + return -ENODEV; + } + } /* else subfunction is already activated */ + + isapnpcfg->irq = dev->irq_resource[0].start; + isapnpcfg->dma = dev->dma_resource[0].start; + isapnpcfg->dma2 = dev->dma_resource[1].start; + isapnpcfg->io_base = dev->resource[0].start; + if (probe_cs4232(isapnpcfg,TRUE) == 0) { + printk(KERN_ERR "cs4232: ISA PnP card found, but not detected?\n"); + return -ENODEV; + } + attach_cs4232(isapnpcfg); + pci_set_drvdata(dev,isapnpcfg); + return 0; +} + static int __init init_cs4232(void) { #ifdef CONFIG_SOUND_WAVEFRONT_MODULE if(synthio == -1) - printk(KERN_WARNING "cs4232: set synthio and synthirq to use the wavefront facilities.\n"); + printk(KERN_INFO "cs4232: set synthio and synthirq to use the wavefront facilities.\n"); else { synth_base = synthio; synth_irq = synthirq; @@ -347,6 +424,13 @@ static int __init init_cs4232(void) if(synthio != -1) printk(KERN_WARNING "cs4232: wavefront support not enabled in this driver.\n"); #endif + cfg.irq = -1; + + if (isapnp && + (isapnp_probe_devs(isapnp_cs4232_list, cs4232_isapnp_probe) > 0) + ) + return 0; + if(io==-1||irq==-1||dma==-1) { printk(KERN_ERR "cs4232: Must set io, irq and dma.\n"); @@ -367,16 +451,27 @@ static int __init init_cs4232(void) probe_cs4232_mpu(&cfg_mpu); /* Bug always returns 0 not OK -- AC */ } - if (probe_cs4232(&cfg) == 0) + if (probe_cs4232(&cfg,FALSE) == 0) return -ENODEV; attach_cs4232(&cfg); return 0; } +int cs4232_isapnp_remove(struct pci_dev *dev, const struct isapnp_device_id *id) +{ + struct address_info *cfg = (struct address_info*)pci_get_drvdata(dev); + if (cfg) unload_cs4232(cfg); + pci_set_drvdata(dev,NULL); + dev->deactivate(dev); + return 0; +} + static void __exit cleanup_cs4232(void) { - unload_cs4232(&cfg); /* unloads MPU as well, if needed */ + isapnp_probe_devs(isapnp_cs4232_list, cs4232_isapnp_remove); + if (cfg.irq != -1) + unload_cs4232(&cfg); /* Unloads global MPU as well, if needed */ } module_init(init_cs4232); @@ -387,6 +482,10 @@ static int __init setup_cs4232(char *str) { /* io, irq, dma, dma2 mpuio, mpuirq*/ int ints[7]; + + /* If we have isapnp cards, no need for options */ + if (isapnp_probe_devs(isapnp_cs4232_list, cs4232_isapnp_probe) > 0) + return 1; str = get_options(str, ARRAY_SIZE(ints), ints); diff --git a/drivers/sound/cs4232.h b/drivers/sound/cs4232.h index 7b5782199c7f..73377b431699 100644 --- a/drivers/sound/cs4232.h +++ b/drivers/sound/cs4232.h @@ -5,7 +5,7 @@ * */ -int probe_cs4232 (struct address_info *hw_config); +int probe_cs4232 (struct address_info *hw_config,int useisapnp); void attach_cs4232 (struct address_info *hw_config); int probe_cs4232_mpu (struct address_info *hw_config); void attach_cs4232_mpu (struct address_info *hw_config); diff --git a/drivers/sound/cs46xx.c b/drivers/sound/cs46xx.c index 55f838bb92e9..410af9aaeca0 100644 --- a/drivers/sound/cs46xx.c +++ b/drivers/sound/cs46xx.c @@ -383,8 +383,8 @@ static int cs_hardware_init(struct cs_card *card); static int cs46xx_powerup(struct cs_card *card, unsigned int type); static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag); static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type); -static void cs46xx_suspend_tbl(struct pci_dev *pcidev); -static void cs46xx_resume_tbl(struct pci_dev *pcidev); +static int cs46xx_suspend_tbl(struct pci_dev *pcidev, u32 state); +static int cs46xx_resume_tbl(struct pci_dev *pcidev); static inline unsigned ld2(unsigned int x) { @@ -3655,7 +3655,7 @@ static int cs46xx_restart_part(struct cs_card *card) static void cs461x_reset(struct cs_card *card); static void cs461x_proc_stop(struct cs_card *card); -static int cs46xx_suspend(struct cs_card *card) +static int cs46xx_suspend(struct cs_card *card, u32 state) { unsigned int tmp; CS_DBGOUT(CS_PM | CS_FUNCTION, 4, @@ -4174,7 +4174,7 @@ static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int list_for_each(entry, &cs46xx_devs) { card = list_entry(entry, struct cs_card, list); - cs46xx_suspend(card); + cs46xx_suspend(card, 0); } } @@ -5665,7 +5665,7 @@ int cs46xx_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) case PM_SUSPEND: CS_DBGOUT(CS_PM, 2, printk(KERN_INFO "cs46xx: PM suspend request\n")); - if(cs46xx_suspend(card)) + if(cs46xx_suspend(card, 0)) { CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO "cs46xx: PM suspend request refused\n")); @@ -5694,7 +5694,7 @@ static int cs46xx_suspend_tbl(struct pci_dev *pcidev, u32 state) struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev); CS_DBGOUT(CS_PM | CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs46xx_suspend_tbl request\n")); - cs46xx_suspend(s); + cs46xx_suspend(s, 0); return 0; } diff --git a/drivers/sound/emu10k1/audio.c b/drivers/sound/emu10k1/audio.c index a90451ccb9b9..cf2c66f8224a 100644 --- a/drivers/sound/emu10k1/audio.c +++ b/drivers/sound/emu10k1/audio.c @@ -903,33 +903,46 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned case SNDCTL_COPR_LOAD: { - copr_buffer buf; + copr_buffer *buf; u32 i; + int ret = -EFAULT; DPF(2, "SNDCTL_COPR_LOAD:\n"); + + buf = kmalloc(sizeof(copr_buffer), GFP_KERNEL); + if(buf == NULL) + return -ENOMEM; + + if (copy_from_user(buf, (copr_buffer *) arg, sizeof(buf))) + goto fail; + + if ((buf->command != 1) && (buf->command != 2)) + { + ret = -EINVAL; + goto fail; + } - if (copy_from_user(&buf, (copr_buffer *) arg, sizeof(buf))) - return -EFAULT; - - if ((buf.command != 1) && (buf.command != 2)) - return -EINVAL; - - if ((buf.offs < 0x100) - || (buf.offs < 0x000) - || (buf.offs + buf.len > 0x800) || (buf.len > 1000)) - return -EINVAL; - - if (buf.command == 1) { - for (i = 0; i < buf.len; i++) - ((u32 *) buf.data)[i] = sblive_readptr(wave_dev->card, buf.offs + i, 0); + if ((buf->offs < 0x100) + || (buf->offs < 0x000) + || (buf->offs + buf->len > 0x800) || (buf->len > 1000)) + { + ret = -EINVAL; + goto fail; + } + if (buf->command == 1) { + for (i = 0; i < buf->len; i++) + ((u32 *) buf->data)[i] = sblive_readptr(wave_dev->card, buf->offs + i, 0); - if (copy_to_user((copr_buffer *) arg, &buf, sizeof(buf))) - return -EFAULT; + if (copy_to_user((copr_buffer *) arg, buf, sizeof(buf))) + goto fail; } else { - for (i = 0; i < buf.len; i++) - sblive_writeptr(wave_dev->card, buf.offs + i, 0, ((u32 *) buf.data)[i]); + for (i = 0; i < buf->len; i++) + sblive_writeptr(wave_dev->card, buf->offs + i, 0, ((u32 *) buf->data)[i]); } - break; + ret = 0; + fail: + kfree(buf); + return ret; } default: /* Default is unrecognized command */ diff --git a/drivers/sound/via82cxxx_audio.c b/drivers/sound/via82cxxx_audio.c index 9d8ea2cdd634..ddbc04a08649 100644 --- a/drivers/sound/via82cxxx_audio.c +++ b/drivers/sound/via82cxxx_audio.c @@ -39,6 +39,9 @@ #include <asm/uaccess.h> #include <asm/hardirq.h> #include <asm/semaphore.h> +#include "sound_config.h" +#include "dev_table.h" +#include "mpu401.h" #undef VIA_DEBUG /* define to enable debugging output and checks */ @@ -178,6 +181,8 @@ #define VIA_CR42_MIDI_ENABLE 0x02 #define VIA_CR42_FM_ENABLE 0x04 #define VIA_CR42_GAME_ENABLE 0x08 +#define VIA_CR42_MIDI_IRQMASK 0x40 +#define VIA_CR42_MIDI_PNP 0x80 #define VIA_CR44_SECOND_CODEC_SUPPORT (1 << 6) #define VIA_CR44_AC_LINK_ACCESS (1 << 7) @@ -290,6 +295,11 @@ struct via_info { struct via_channel ch_in; struct via_channel ch_out; struct via_channel ch_fm; + +#ifdef CONFIG_MIDI_VIA82CXXX + void *midi_devc; + struct address_info midi_info; +#endif }; @@ -720,12 +730,10 @@ static int via_chan_buffer_init (struct via_info *card, struct via_channel *chan /* set location of DMA-able scatter-gather info table */ DPRINTK ("outl (0x%X, 0x%04lX)\n", - cpu_to_le32 (chan->sgt_handle), - chan->iobase + VIA_PCM_TABLE_ADDR); + chan->sgt_handle, chan->iobase + VIA_PCM_TABLE_ADDR); via_ac97_wait_idle (card); - outl (cpu_to_le32 (chan->sgt_handle), - chan->iobase + VIA_PCM_TABLE_ADDR); + outl (chan->sgt_handle, chan->iobase + VIA_PCM_TABLE_ADDR); udelay (20); via_ac97_wait_idle (card); @@ -1216,25 +1224,28 @@ static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg) card = codec->private_data; - data = (reg << 16) | VIA_CR80_READ; + /* Every time we write to register 80 we cause a transaction. + The only safe way to clear the valid bit is to write it at + the same time as the command */ + data = (reg << 16) | VIA_CR80_READ | VIA_CR80_VALID; outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL); - udelay (20); - for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) { - if (inl (card->baseaddr + 0x80) & VIA_CR80_VALID) + udelay (1); + if ((((data = inl(card->baseaddr + 0x80)) & + (VIA_CR80_VALID|VIA_CR80_BUSY)) == VIA_CR80_VALID)) goto out; - - udelay (15); } printk (KERN_WARNING PFX "timeout while reading AC97 codec (0x%lX)\n", data); goto err_out; out: + /* Once the valid bit has become set, we must wait a complete AC97 + frame before the data has settled. */ + udelay(25); data = (unsigned long) inl (card->baseaddr + 0x80); - outb (0x02, card->baseaddr + 0x83); - + if (((data & 0x007F0000) >> 16) == reg) { DPRINTK ("EXIT, success, data=0x%lx, retval=0x%lx\n", data, data & 0x0000FFFF); @@ -1371,7 +1382,6 @@ static struct file_operations via_mixer_fops = { static int __init via_ac97_reset (struct via_info *card) { struct pci_dev *pdev = card->pdev; - u8 tmp8; u16 tmp16; DPRINTK ("ENTER\n"); @@ -1569,10 +1579,10 @@ static void via_intr_channel (struct via_channel *chan) * and advance the h/w ptr, wrapping around to zero if needed */ if (n == (chan->frag_number - 1)) { - chan->sgtable[n].count = (chan->frag_size | VIA_EOL); + chan->sgtable[n].count = cpu_to_le32(chan->frag_size | VIA_EOL); atomic_set (&chan->hw_ptr, 0); } else { - chan->sgtable[n].count = (chan->frag_size | VIA_FLAG); + chan->sgtable[n].count = cpu_to_le32(chan->frag_size | VIA_FLAG); atomic_inc (&chan->hw_ptr); } @@ -1628,8 +1638,12 @@ static void via_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ status32 = inl (card->baseaddr + VIA_BASE0_SGD_STATUS_SHADOW); if (!(status32 & VIA_INTR_MASK)) + { +#ifdef CONFIG_MIDI_VIA82CXXX + uart401intr(irq, card->midi_devc, regs); +#endif return; - + } DPRINTK ("intr, status32 == 0x%08X\n", status32); /* synchronize interrupt handling under SMP. this spinlock @@ -1781,10 +1795,8 @@ static int __init via_dsp_init (struct via_info *card) /* turn off legacy features, if not already */ pci_read_config_byte (card->pdev, VIA_FUNC_ENABLE, &tmp8); - if (tmp8 & (VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE | - VIA_CR42_FM_ENABLE)) { - tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE | - VIA_CR42_FM_ENABLE); + if (tmp8 & (VIA_CR42_SB_ENABLE | VIA_CR42_FM_ENABLE)) { + tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_FM_ENABLE); pci_write_config_byte (card->pdev, VIA_FUNC_ENABLE, tmp8); } @@ -2682,6 +2694,7 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, /* wait until all buffers have been played, and then stop device */ case SNDCTL_DSP_SYNC: DPRINTK ("DSP_SYNC\n"); + rc = 0; if (wr) { DPRINTK ("SYNC EXIT (after calling via_dsp_drain_playback)\n"); rc = via_dsp_drain_playback (card, &card->ch_out, nonblock); @@ -3010,6 +3023,9 @@ static int via_dsp_release(struct inode *inode, struct file *file) static int __init via_init_one (struct pci_dev *pdev, const struct pci_device_id *id) { +#ifdef CONFIG_MIDI_VIA82CXXX + u8 r42; +#endif int rc; struct via_info *card; static int printed_version = 0; @@ -3019,25 +3035,19 @@ static int __init via_init_one (struct pci_dev *pdev, const struct pci_device_id if (printed_version++ == 0) printk (KERN_INFO "Via 686a audio driver " VIA_VERSION "\n"); - if (pci_enable_device (pdev)) { - rc = -EIO; - goto err_out_none; - } - - if (!request_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0), - VIA_MODULE_NAME)) { - printk (KERN_ERR PFX "unable to obtain I/O resources, aborting\n"); - rc = -EBUSY; + rc = pci_enable_device (pdev); + if (rc) goto err_out; - } + rc = pci_request_regions (pdev, "via82cxxx_audio"); + if (rc) + goto err_out_disable; card = kmalloc (sizeof (*card), GFP_KERNEL); if (!card) { printk (KERN_ERR PFX "out of memory, aborting\n"); rc = -ENOMEM; - goto err_out_none; + goto err_out_res; } pci_set_drvdata (pdev, card); @@ -3111,6 +3121,34 @@ static int __init via_init_one (struct pci_dev *pdev, const struct pci_device_id printk (KERN_INFO PFX "board #%d at 0x%04lX, IRQ %d\n", card->card_num + 1, card->baseaddr, pdev->irq); +#ifdef CONFIG_MIDI_VIA82CXXX + /* Disable by default */ + card->midi_info.io_base = 0; + + pci_read_config_byte (pdev, 0x42, &r42); + /* Disable MIDI interrupt */ + pci_write_config_byte (pdev, 0x42, r42 | VIA_CR42_MIDI_IRQMASK); + if (r42 & VIA_CR42_MIDI_ENABLE) + { + if (r42 & VIA_CR42_MIDI_PNP) /* Address selected by iobase 2 - not tested */ + card->midi_info.io_base = pci_resource_start (pdev, 2); + else /* Address selected by byte 0x43 */ + { + u8 r43; + pci_read_config_byte (pdev, 0x43, &r43); + card->midi_info.io_base = 0x300 + ((r43 & 0x0c) << 2); + } + + card->midi_info.irq = -pdev->irq; + if (probe_uart401(& card->midi_info, THIS_MODULE)) + { + card->midi_devc=midi_devs[card->midi_info.slots[4]]->devc; + pci_write_config_byte(pdev, 0x42, r42 & ~VIA_CR42_MIDI_IRQMASK); + printk("Enabled Via MIDI\n"); + } + } +#endif + DPRINTK ("EXIT, returning 0\n"); return 0; @@ -3129,8 +3167,12 @@ err_out_kfree: #endif kfree (card); -err_out_none: - release_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0)); +err_out_res: + pci_release_regions (pdev); + +err_out_disable: + pci_disable_device (pdev); + err_out: pci_set_drvdata (pdev, NULL); DPRINTK ("EXIT - returning %d\n", rc); @@ -3148,13 +3190,16 @@ static void __exit via_remove_one (struct pci_dev *pdev) card = pci_get_drvdata (pdev); assert (card != NULL); +#ifdef CONFIG_MIDI_VIA82CXXX + if (card->midi_info.io_base) + unload_uart401(&card->midi_info); +#endif + via_interrupt_cleanup (card); via_card_cleanup_proc (card); via_dsp_cleanup (card); via_ac97_cleanup (card); - release_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0)); - #ifndef VIA_NDEBUG memset (card, 0xAB, sizeof (*card)); /* poison memory */ #endif @@ -3162,7 +3207,9 @@ static void __exit via_remove_one (struct pci_dev *pdev) pci_set_drvdata (pdev, NULL); + pci_release_regions (pdev); pci_set_power_state (pdev, 3); /* ...zzzzzz */ + pci_disable_device (pdev); DPRINTK ("EXIT\n"); return; diff --git a/drivers/usb/se401.c b/drivers/usb/se401.c index 541bf8c00202..f326bef41990 100644 --- a/drivers/usb/se401.c +++ b/drivers/usb/se401.c @@ -49,6 +49,7 @@ static const char version[] = "0.22"; #include "se401.h" static int flickerless=0; +static int video_nr = -1; #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 3, 0) static __devinitdata struct usb_device_id device_table [] = { @@ -63,12 +64,11 @@ static __devinitdata struct usb_device_id device_table [] = { MODULE_DEVICE_TABLE(usb, device_table); #endif -static int video_nr = -1; - MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>"); MODULE_DESCRIPTION("SE401 USB Camera Driver"); MODULE_PARM(flickerless, "i"); MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)"); +MODULE_PARM(video_nr, "i"); EXPORT_NO_SYMBOLS; @@ -1286,6 +1286,9 @@ static int se401_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) if (copy_from_user((void *)&frame, arg, sizeof(int))) return -EFAULT; + if(frame <0 || frame >= SE401_NUMFRAMES) + return -EINVAL; + ret=se401_newframe(se401, frame); se401->frame[frame].grabstate=FRAME_UNUSED; return ret; diff --git a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c index e1b713040b10..17504fbf50d8 100644 --- a/drivers/video/aty128fb.c +++ b/drivers/video/aty128fb.c @@ -111,7 +111,6 @@ static struct fb_var_screeninfo default_var = { }; #endif /* CONFIG_PPC */ -#ifndef MODULE /* default modedb mode */ /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ static struct fb_videomode defaultmode __initdata = { @@ -128,7 +127,6 @@ static struct fb_videomode defaultmode __initdata = { sync: 0, vmode: FB_VMODE_NONINTERLACED }; -#endif /* MODULE */ /* struct to hold chip description information */ struct aty128_chip_info { @@ -213,11 +211,13 @@ static const struct aty128_meminfo ddr_sgram = static const char *aty128fb_name = "ATY Rage128"; static char fontname[40] __initdata = { 0 }; + static int noaccel __initdata = 0; +static char *font __initdata = NULL; +static char *mode __initdata = NULL; +static int nomtrr __initdata = 0; -#ifndef MODULE static const char *mode_option __initdata = NULL; -#endif #ifdef CONFIG_PPC static int default_vmode __initdata = VMODE_1024_768_60; @@ -528,7 +528,7 @@ aty_pll_wait_readupdate(const struct fb_info_aty128 *info) } if (reset) /* reset engine?? */ - printk(KERN_DEBUG "aty128fb: PLL write timeout!"); + printk(KERN_DEBUG "aty128fb: PLL write timeout!\n"); } @@ -1605,7 +1605,6 @@ aty128fb_rasterimg(struct fb_info *info, int start) } -#ifndef MODULE int __init aty128fb_setup(char *options) { @@ -1663,7 +1662,6 @@ aty128fb_setup(char *options) } return 0; } -#endif /* !MODULE */ /* @@ -1710,10 +1708,7 @@ aty128_init(struct fb_info_aty128 *info, const char *name) info->fb_info.blank = &aty128fbcon_blank; info->fb_info.flags = FBINFO_FLAG_DEFAULT; -#ifdef MODULE var = default_var; -#else - memset(&var, 0, sizeof(var)); #ifdef CONFIG_PPC if (_machine == _MACH_Pmac) { if (mode_option) { @@ -1736,7 +1731,6 @@ aty128_init(struct fb_info_aty128 *info, const char *name) &defaultmode, 8) == 0) var = default_var; } -#endif /* MODULE */ if (noaccel) var.accel_flags &= ~FB_ACCELF_TEXT; @@ -2598,10 +2592,39 @@ static struct display_switch fbcon_aty128_32 = { #ifdef MODULE MODULE_AUTHOR("(c)1999-2000 Brad Douglas <brad@neruo.com>"); MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards"); +MODULE_PARM(noaccel, "i"); +MODULE_PARM_DESC(noaccel, "Disable hardware acceleration (0 or 1=disabled) (default=0)"); +MODULE_PARM(font, "s"); +MODULE_PARM_DESC(font, "Specify one of the compiled-in fonts (default=none)"); +MODULE_PARM(mode, "s"); +MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); +#ifdef CONFIG_MTRR +MODULE_PARM(nomtrr, "i"); +MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)"); +#endif int __init init_module(void) { + if (noaccel) { + noaccel = 1; + printk(KERN_INFO "aty128fb: Parameter NOACCEL set\n"); + } + if (font) { + strncpy(fontname, font, sizeof(fontname)-1); + printk(KERN_INFO "aty128fb: Parameter FONT set to %s\n", font); + } + if (mode) { + mode_option = mode; + printk(KERN_INFO "aty128fb: Parameter MODE set to %s\n", mode); + } +#ifdef CONFIG_MTRR + if (nomtrr) { + mtrr = 0; + printk(KERN_INFO "aty128fb: Parameter NOMTRR set\n"); + } +#endif + aty128fb_init(); return 0; } diff --git a/fs/Config.in b/fs/Config.in index e65babe9d566..6aa589c98d22 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -27,8 +27,8 @@ dep_tristate ' UMSDOS: Unix-like file system on top of standard MSDOS fs' CON dep_tristate ' VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS dep_tristate 'EFS file system support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL dep_tristate 'Journalling Flash File System (JFFS) support (EXPERIMENTAL)' CONFIG_JFFS_FS $CONFIG_EXPERIMENTAL $CONFIG_MTD -if [ "$CONFIG_JFFS_FS" != "n" ] ; then - int 'JFFS debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_JFFS_FS_VERBOSE 0 +if [ "$CONFIG_JFFS_FS" = "y" -o "$CONFIG_JFFS_FS" = "m" ] ; then + int 'JFFS debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_JFFS_FS_VERBOSE 0 fi tristate 'Compressed ROM file system support' CONFIG_CRAMFS bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS @@ -64,8 +64,7 @@ tristate 'ROM file system support' CONFIG_ROMFS_FS tristate 'Second extended fs support' CONFIG_EXT2_FS -tristate 'System V and Coherent file system support (read only)' CONFIG_SYSV_FS -dep_mbool ' SYSV file system write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE $CONFIG_SYSV_FS $CONFIG_EXPERIMENTAL +tristate 'System V/Xenix/V7/Coherent file system support' CONFIG_SYSV_FS tristate 'UDF file system support (read only)' CONFIG_UDF_FS dep_mbool ' UDF write support (DANGEROUS)' CONFIG_UDF_RW $CONFIG_UDF_FS $CONFIG_EXPERIMENTAL diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index f1fbe9696338..a59e4998335e 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -396,7 +396,7 @@ out: static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct file *interpreter = NULL; /* to shut gcc up */ - unsigned long load_addr = 0, load_bias; + unsigned long load_addr = 0, load_bias = 0; int load_addr_set = 0; char * elf_interpreter = NULL; unsigned int interpreter_type = INTERPRETER_NONE; @@ -595,12 +595,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) setup_arg_pages(bprm); /* XXX: check error */ current->mm->start_stack = bprm->p; - /* Try and get dynamic programs out of the way of the default mmap - base, as well as whatever program they might try to exec. This - is because the brk will follow the loader, and is not movable. */ - - load_bias = ELF_PAGESTART(elf_ex.e_type==ET_DYN ? ELF_ET_DYN_BASE : 0); - /* Now we do a little grungy work by mmaping the ELF image into the correct location in memory. At this point, we assume that the image should be loaded at fixed address, not at a variable @@ -624,6 +618,11 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) vaddr = elf_ppnt->p_vaddr; if (elf_ex.e_type == ET_EXEC || load_addr_set) { elf_flags |= MAP_FIXED; + } else if (elf_ex.e_type == ET_DYN) { + /* Try and get dynamic programs out of the way of the default mmap + base, as well as whatever program they might try to exec. This + is because the brk will follow the loader, and is not movable. */ + load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); } error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); diff --git a/fs/buffer.c b/fs/buffer.c index 480903405789..89c3c6d9d60d 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -168,14 +168,25 @@ static void end_buffer_write(struct buffer_head *bh, int uptodate) unlock_buffer(bh); } -/* The buffers have been marked clean and locked. Just submit the dang things.. */ +/* + * The buffers have been marked clean and locked. Just submit the dang + * things.. + * + * We'll wait for the first one of them - "sync" is not exactly + * performance-critical, and this makes us not hog the IO subsystem + * completely, while still allowing for a fair amount of concurrent IO. + */ static void write_locked_buffers(struct buffer_head **array, unsigned int count) { + struct buffer_head *wait = *array; + atomic_inc(&wait->b_count); do { struct buffer_head * bh = *array++; bh->b_end_io = end_buffer_write; submit_bh(WRITE, bh); } while (--count); + wait_on_buffer(wait); + atomic_dec(&wait->b_count); } #define NRSYNC (32) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 0153c66f149a..546f2e38e35e 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -428,7 +428,7 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino, * fh must be initialized before calling fh_compose */ fh_init(&fh, maxsize); - if (fh_compose(&fh, exp, dget(nd.dentry))) + if (fh_compose(&fh, exp, dget(nd.dentry), NULL)) err = -EINVAL; else err = 0; diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 1cc559ea9fc3..7832d3799d75 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -91,7 +91,8 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp, SVCFH_fmt(&argp->fh)); fh_copy(&resp->fh, &argp->fh); - nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs); + nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs, + argp->check_guard, argp->guardtime); RETURN_STATUS(nfserr); } diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index a2ac35ac66db..e62925e2ceb3 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -716,7 +716,7 @@ encode_entry(struct readdir_cd *cd, const char *name, dchild = lookup_one_len(name, dparent,namlen); if (IS_ERR(dchild)) goto noexec; - if (fh_compose(&fh, exp, dchild) != 0 || !dchild->d_inode) + if (fh_compose(&fh, exp, dchild, cd->dirfh) != 0 || !dchild->d_inode) goto noexec; p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry); *p++ = xdr_one; /* yes, a file handle follows */ diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 86b82cc5ffdc..b8e815864151 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -743,9 +743,31 @@ inline int _fh_update(struct dentry *dentry, struct svc_export *exp, return 2; } +/* + * for composing old style file handles + */ +inline void _fh_update_old(struct dentry *dentry, struct svc_export *exp, + struct knfsd_fh *fh) +{ + fh->ofh_ino = ino_t_to_u32(dentry->d_inode->i_ino); + fh->ofh_generation = dentry->d_inode->i_generation; + if (S_ISDIR(dentry->d_inode->i_mode) || + (exp->ex_flags & NFSEXP_NOSUBTREECHECK)) + fh->ofh_dirino = 0; +} + int -fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry) +fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, struct svc_fh *ref_fh) { + /* ref_fh is a reference file handle. + * if it is non-null, then we should compose a filehandle which is + * of the same version, where possible. + * Currently, that means that if ref_fh->fh_handle.fh_version == 0xca + * Then create a 32byte filehandle using nfs_fhbase_old + * But only do this if dentry_to_fh is not available + * + */ + struct inode * inode = dentry->d_inode; struct dentry *parent = dentry->d_parent; __u32 *datap; @@ -766,20 +788,32 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry) fhp->fh_dentry = dentry; /* our internal copy */ fhp->fh_export = exp; - fhp->fh_handle.fh_version = 1; - fhp->fh_handle.fh_auth_type = 0; - fhp->fh_handle.fh_fsid_type = 0; - datap = fhp->fh_handle.fh_auth+0; - /* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */ - *datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev)); - *datap++ = ino_t_to_u32(exp->ex_ino); - - if (inode) - fhp->fh_handle.fh_fileid_type = - _fh_update(dentry, exp, &datap, fhp->fh_maxsize-3); - - fhp->fh_handle.fh_size = (datap-fhp->fh_handle.fh_auth+1)*4; - + if (ref_fh && + ref_fh->fh_handle.fh_version == 0xca && + parent->d_inode->i_sb->s_op->dentry_to_fh == NULL) { + /* old style filehandle please */ + memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE); + fhp->fh_handle.fh_size = NFS_FHSIZE; + fhp->fh_handle.ofh_dcookie = 0xfeebbaca; + fhp->fh_handle.ofh_dev = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev)); + fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev; + fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_ino); + fhp->fh_handle.ofh_dirino = ino_t_to_u32(dentry->d_parent->d_inode->i_ino); + if (inode) + _fh_update_old(dentry, exp, &fhp->fh_handle); + } else { + fhp->fh_handle.fh_version = 1; + fhp->fh_handle.fh_auth_type = 0; + fhp->fh_handle.fh_fsid_type = 0; + datap = fhp->fh_handle.fh_auth+0; + /* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */ + *datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev)); + *datap++ = ino_t_to_u32(exp->ex_ino); + if (inode) + fhp->fh_handle.fh_fileid_type = + _fh_update(dentry, exp, &datap, fhp->fh_maxsize-3); + fhp->fh_handle.fh_size = (datap-fhp->fh_handle.fh_auth+1)*4; + } nfsd_nr_verified++; if (fhp->fh_handle.fh_fileid_type == 255) @@ -805,11 +839,15 @@ fh_update(struct svc_fh *fhp) goto out_negative; if (fhp->fh_handle.fh_fileid_type != 0) goto out_uptodate; - datap = fhp->fh_handle.fh_auth+ - fhp->fh_handle.fh_size/4 -1; - fhp->fh_handle.fh_fileid_type = - _fh_update(dentry, fhp->fh_export, &datap, fhp->fh_maxsize-fhp->fh_handle.fh_size); - fhp->fh_handle.fh_size = (datap-fhp->fh_handle.fh_auth+1)*4; + if (fhp->fh_handle.fh_version != 1) { + _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle); + } else { + datap = fhp->fh_handle.fh_auth+ + fhp->fh_handle.fh_size/4 -1; + fhp->fh_handle.fh_fileid_type = + _fh_update(dentry, fhp->fh_export, &datap, fhp->fh_maxsize-fhp->fh_handle.fh_size); + fhp->fh_handle.fh_size = (datap-fhp->fh_handle.fh_auth+1)*4; + } out: return 0; diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 2e437e7f2845..a3afc598e823 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -71,7 +71,7 @@ nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp, argp->attrs.ia_valid, (long) argp->attrs.ia_size); fh_copy(&resp->fh, &argp->fh); - return nfsd_setattr(rqstp, &resp->fh, &argp->attrs); + return nfsd_setattr(rqstp, &resp->fh, &argp->attrs,0, (time_t)0); } /* @@ -222,7 +222,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, goto out_unlock; } fh_init(newfhp, NFS_FHSIZE); - nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild); + nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp); if (!nfserr && !dchild->d_inode) nfserr = nfserr_noent; if (nfserr) { @@ -331,7 +331,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, */ attr->ia_valid &= ATTR_SIZE; if (attr->ia_valid) - nfserr = nfsd_setattr(rqstp, newfhp, attr); + nfserr = nfsd_setattr(rqstp, newfhp, attr, 0, (time_t)0); } out_unlock: diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index b8c2d4a4a69f..fdc90401d700 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -176,7 +176,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, * Note: we compose the file handle now, but as the * dentry may be negative, it may need to be updated. */ - err = fh_compose(resfh, exp, dentry); + err = fh_compose(resfh, exp, dentry, fhp); if (!err && !dentry->d_inode) err = nfserr_noent; out: @@ -192,7 +192,8 @@ out_nfserr: * N.B. After this call fhp needs an fh_put */ int -nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap) +nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, + int check_guard, time_t guardtime) { struct dentry *dentry; struct inode *inode; @@ -310,21 +311,23 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap) fh_lock(fhp); size_change = 1; } + err = nfserr_notsync; + if (!check_guard || guardtime == inode->i_ctime) { #ifdef CONFIG_QUOTA - if (iap->ia_valid & (ATTR_UID|ATTR_GID)) - err = DQUOT_TRANSFER(dentry, iap); - else + if (iap->ia_valid & (ATTR_UID|ATTR_GID)) + err = DQUOT_TRANSFER(dentry, iap); + else #endif - err = notify_change(dentry, iap); + err = notify_change(dentry, iap); + err = nfserrno(err); + } if (size_change) { fh_unlock(fhp); put_write_access(inode); } - if (err) - goto out_nfserr; - if (EX_ISSYNC(fhp->fh_export)) - write_inode_now(inode, 1); - err = 0; + if (!err) + if (EX_ISSYNC(fhp->fh_export)) + write_inode_now(inode, 1); out: return err; @@ -849,7 +852,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, err = PTR_ERR(dchild); if (IS_ERR(dchild)) goto out_nfserr; - err = fh_compose(resfhp, fhp->fh_export, dchild); + err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); if (err) goto out; } else { @@ -916,7 +919,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, */ err = 0; if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) - err = nfsd_setattr(rqstp, resfhp, iap); + err = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); /* * Update the file handle to get the new inode info. */ @@ -975,7 +978,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, if (IS_ERR(dchild)) goto out_nfserr; - err = fh_compose(resfhp, fhp->fh_export, dchild); + err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); if (err) goto out; @@ -1051,7 +1054,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, */ set_attr: if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) - err = nfsd_setattr(rqstp, resfhp, iap); + err = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); out: fh_unlock(fhp); @@ -1159,7 +1162,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, fh_unlock(fhp); /* Compose the fh so the dentry will be freed ... */ - cerr = fh_compose(resfhp, fhp->fh_export, dnew); + cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); if (err==0) err = cerr; out: return err; diff --git a/fs/proc/generic.c b/fs/proc/generic.c index e31efb051019..24c095bc980e 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -190,7 +190,7 @@ static int xlate_proc_name(const char *name, return 0; } -static unsigned long proc_alloc_map[PROC_NDYNAMIC / 8]; +static unsigned long proc_alloc_map[(PROC_NDYNAMIC + BITS_PER_LONG - 1) / BITS_PER_LONG]; spinlock_t proc_alloc_map_lock = SPIN_LOCK_UNLOCKED; diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 654ada814209..f78595996c26 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1284,7 +1284,12 @@ void reiserfs_write_inode (struct inode * inode, int do_sync) { inode->i_ino) ; return ; } - if (do_sync) { + /* memory pressure can sometimes initiate write_inode calls with sync == 1, + ** these cases are just when the system needs ram, not when the + ** inode needs to reach disk for safety, and they can safely be + ** ignored because the altered inode has already been logged. + */ + if (do_sync && !(current->flags & PF_MEMALLOC)) { lock_kernel() ; journal_begin(&th, inode->i_sb, jbegin_count) ; reiserfs_update_sd (&th, inode); diff --git a/fs/sysv/Makefile b/fs/sysv/Makefile index 9eed30c9cfd3..997a9d3226bf 100644 --- a/fs/sysv/Makefile +++ b/fs/sysv/Makefile @@ -9,7 +9,7 @@ O_TARGET := sysv.o -obj-y := ialloc.o balloc.o inode.o file.o dir.o namei.o fsync.o truncate.o +obj-y := ialloc.o balloc.o inode.o itree.o file.o dir.o namei.o super.o obj-m := $(O_TARGET) include $(TOPDIR)/Rules.make diff --git a/fs/sysv/balloc.c b/fs/sysv/balloc.c index 978bc2a91be9..c9b2f90462ad 100644 --- a/fs/sysv/balloc.c +++ b/fs/sysv/balloc.c @@ -19,311 +19,201 @@ * This file contains code for allocating/freeing blocks. */ -#include <linux/kernel.h> #include <linux/fs.h> #include <linux/sysv_fs.h> -#include <linux/string.h> #include <linux/locks.h> /* We don't trust the value of - sb->sv_sbd2->s_tfree = *sb->sv_sb_total_free_blocks + sb->sv_sbd2->s_tfree = *sb->sv_free_blocks but we nevertheless keep it up to date. */ -void sysv_free_block(struct super_block * sb, unsigned int block) +static inline u32 *get_chunk(struct super_block *sb, struct buffer_head *bh) +{ + char *bh_data = bh->b_data; + + if (sb->sv_type == FSTYPE_SYSV4) + return (u32*)(bh_data+4); + else + return (u32*)(bh_data+2); +} + +/* NOTE NOTE NOTE: nr is a block number _as_ _stored_ _on_ _disk_ */ + +void sysv_free_block(struct super_block * sb, u32 nr) { struct buffer_head * bh; - char * bh_data; + u32 *blocks = sb->sv_bcache; + unsigned count; + unsigned block = fs32_to_cpu(sb, nr); - if (!sb) { - printk("sysv_free_block: trying to free block on nonexistent device\n"); - return; - } if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) { printk("sysv_free_block: trying to free block not in datazone\n"); return; } + lock_super(sb); - if (*sb->sv_sb_flc_count > sb->sv_flc_size) { + count = fs16_to_cpu(sb, *sb->sv_bcache_count); + + if (count > sb->sv_flc_size) { printk("sysv_free_block: flc_count > flc_size\n"); unlock_super(sb); return; } /* If the free list head in super-block is full, it is copied - * into this block being freed: + * into this block being freed, ditto if it's completely empty + * (applies only on Coherent). */ - if (*sb->sv_sb_flc_count == sb->sv_flc_size) { - u16 * flc_count; - u32 * flc_blocks; - - bh = sv_getblk(sb, sb->s_dev, block); + if (count == sb->sv_flc_size || count == 0) { + block += sb->sv_block_base; + bh = getblk(sb->s_dev, block, sb->s_blocksize); if (!bh) { printk("sysv_free_block: getblk() failed\n"); unlock_super(sb); return; } - bh_data = bh->b_data; - switch (sb->sv_type) { - case FSTYPE_XENIX: - flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree; - flc_blocks = &((struct xenix_freelist_chunk *) bh_data)->fl_free[0]; - break; - case FSTYPE_SYSV4: - flc_count = &((struct sysv4_freelist_chunk *) bh_data)->fl_nfree; - flc_blocks = &((struct sysv4_freelist_chunk *) bh_data)->fl_free[0]; - break; - case FSTYPE_SYSV2: - flc_count = &((struct sysv2_freelist_chunk *) bh_data)->fl_nfree; - flc_blocks = &((struct sysv2_freelist_chunk *) bh_data)->fl_free[0]; - break; - case FSTYPE_COH: - flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree; - flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0]; - break; - default: panic("sysv_free_block: invalid fs type\n"); - } - *flc_count = *sb->sv_sb_flc_count; /* = sb->sv_flc_size */ - memcpy(flc_blocks, sb->sv_sb_flc_blocks, *flc_count * sizeof(sysv_zone_t)); + memset(bh->b_data, 0, sb->s_blocksize); + *(u16*)bh->b_data = cpu_to_fs16(sb, count); + memcpy(get_chunk(sb,bh), blocks, count * sizeof(sysv_zone_t)); mark_buffer_dirty(bh); mark_buffer_uptodate(bh, 1); brelse(bh); - *sb->sv_sb_flc_count = 0; - } else - /* If the free list head in super-block is empty, create a new head - * in this block being freed: - */ - if (*sb->sv_sb_flc_count == 0) { /* Applies only to Coherent FS */ - bh = sv_getblk(sb, sb->s_dev, block); - if (!bh) { - printk("sysv_free_block: getblk() failed\n"); - unlock_super(sb); - return; - } - memset(bh->b_data, 0, sb->sv_block_size); - /* this implies ((struct ..._freelist_chunk *) bh->b_data)->flc_count = 0; */ - mark_buffer_dirty(bh); - mark_buffer_uptodate(bh, 1); - brelse(bh); - /* still *sb->sv_sb_flc_count = 0 */ - } else { - /* Throw away block's contents */ - bh = sv_get_hash_table(sb, sb->s_dev, block); - if (bh) - mark_buffer_clean(bh); - brelse(bh); + count = 0; } - if (sb->sv_convert) - block = to_coh_ulong(block); - sb->sv_sb_flc_blocks[(*sb->sv_sb_flc_count)++] = block; - if (sb->sv_convert) - *sb->sv_sb_total_free_blocks = - to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) + 1); - else - *sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks + 1; - mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */ - if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2); - sb->s_dirt = 1; /* and needs time stamp */ + sb->sv_bcache[count++] = nr; + + *sb->sv_bcache_count = cpu_to_fs16(sb, count); + fs32_add(sb, sb->sv_free_blocks, 1); + dirty_sb(sb); unlock_super(sb); } -int sysv_new_block(struct super_block * sb) +u32 sysv_new_block(struct super_block * sb) { unsigned int block; + u32 nr; struct buffer_head * bh; - char * bh_data; + unsigned count; - if (!sb) { - printk("sysv_new_block: trying to get new block from nonexistent device\n"); - return 0; - } lock_super(sb); - if (*sb->sv_sb_flc_count == 0) { /* Applies only to Coherent FS */ - unlock_super(sb); - return 0; /* no blocks available */ - } - block = sb->sv_sb_flc_blocks[(*sb->sv_sb_flc_count)-1]; - if (sb->sv_convert) - block = from_coh_ulong(block); - if (block == 0) { /* Applies only to Xenix FS, SystemV FS */ - unlock_super(sb); - return 0; /* no blocks available */ - } - (*sb->sv_sb_flc_count)--; + count = fs16_to_cpu(sb, *sb->sv_bcache_count); + + if (count == 0) /* Applies only to Coherent FS */ + goto Enospc; + nr = sb->sv_bcache[--count]; + if (nr == 0) /* Applies only to Xenix FS, SystemV FS */ + goto Enospc; + + block = fs32_to_cpu(sb, nr); + + *sb->sv_bcache_count = cpu_to_fs16(sb, count); + if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) { - printk("sysv_new_block: new block %d is not in data zone\n",block); - unlock_super(sb); - return 0; + printk("sysv_new_block: new block %d is not in data zone\n", + block); + goto Enospc; } - if (*sb->sv_sb_flc_count == 0) { /* the last block continues the free list */ - u16 * flc_count; - u32 * flc_blocks; - if (!(bh = sv_bread(sb, sb->s_dev, block))) { + if (count == 0) { /* the last block continues the free list */ + unsigned count; + + block += sb->sv_block_base; + if (!(bh = bread(sb->s_dev, block, sb->s_blocksize))) { printk("sysv_new_block: cannot read free-list block\n"); /* retry this same block next time */ - (*sb->sv_sb_flc_count)++; - unlock_super(sb); - return 0; + *sb->sv_bcache_count = cpu_to_fs16(sb, 1); + goto Enospc; } - bh_data = bh->b_data; - switch (sb->sv_type) { - case FSTYPE_XENIX: - flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree; - flc_blocks = &((struct xenix_freelist_chunk *) bh_data)->fl_free[0]; - break; - case FSTYPE_SYSV4: - flc_count = &((struct sysv4_freelist_chunk *) bh_data)->fl_nfree; - flc_blocks = &((struct sysv4_freelist_chunk *) bh_data)->fl_free[0]; - break; - case FSTYPE_SYSV2: - flc_count = &((struct sysv2_freelist_chunk *) bh_data)->fl_nfree; - flc_blocks = &((struct sysv2_freelist_chunk *) bh_data)->fl_free[0]; - break; - case FSTYPE_COH: - flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree; - flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0]; - break; - default: panic("sysv_new_block: invalid fs type\n"); - } - if (*flc_count > sb->sv_flc_size) { + count = fs16_to_cpu(sb, *(u16*)bh->b_data); + if (count > sb->sv_flc_size) { printk("sysv_new_block: free-list block with >flc_size entries\n"); brelse(bh); - unlock_super(sb); - return 0; + goto Enospc; } - *sb->sv_sb_flc_count = *flc_count; - memcpy(sb->sv_sb_flc_blocks, flc_blocks, *flc_count * sizeof(sysv_zone_t)); + *sb->sv_bcache_count = cpu_to_fs16(sb, count); + memcpy(sb->sv_bcache, get_chunk(sb, bh), + count * sizeof(sysv_zone_t)); brelse(bh); } /* Now the free list head in the superblock is valid again. */ - bh = sv_getblk(sb, sb->s_dev, block); - if (!bh) { - printk("sysv_new_block: getblk() failed\n"); - unlock_super(sb); - return 0; - } - if (atomic_read(&bh->b_count) != 1) { - printk("sysv_new_block: block already in use\n"); - unlock_super(sb); - return 0; - } - memset(bh->b_data, 0, sb->sv_block_size); - mark_buffer_dirty(bh); - mark_buffer_uptodate(bh, 1); - brelse(bh); - if (sb->sv_convert) - *sb->sv_sb_total_free_blocks = - to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) - 1); - else - *sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks - 1; - mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */ - if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2); - sb->s_dirt = 1; /* and needs time stamp */ + fs32_add(sb, sb->sv_free_blocks, -1); + dirty_sb(sb); + unlock_super(sb); + return nr; + +Enospc: unlock_super(sb); - return block; + return 0; } unsigned long sysv_count_free_blocks(struct super_block * sb) { -#if 1 /* test */ - int count, old_count; - unsigned int block; - struct buffer_head * bh; - char * bh_data; - int i; + int sb_count; + int count; + struct buffer_head * bh = NULL; + u32 *blocks; + unsigned block; + int n; + + lock_super(sb); + sb_count = fs32_to_cpu(sb, *sb->sv_free_blocks); + + if (0) + goto trust_sb; /* this causes a lot of disk traffic ... */ count = 0; - lock_super(sb); - if (*sb->sv_sb_flc_count > 0) { - for (i = *sb->sv_sb_flc_count ; /* i > 0 */ ; ) { - block = sb->sv_sb_flc_blocks[--i]; - if (sb->sv_convert) - block = from_coh_ulong(block); - if (block == 0) /* block 0 terminates list */ - goto done; + n = fs16_to_cpu(sb, *sb->sv_bcache_count); + blocks = sb->sv_bcache; + while (1) { + if (n > sb->sv_flc_size) + goto E2big; + block = 0; + while (n && (block = blocks[--n]) != 0) count++; - if (i == 0) - break; - } - /* block = sb->sv_sb_flc_blocks[0], the last block continues the free list */ - while (1) { - u16 * flc_count; - u32 * flc_blocks; + if (block == 0) + break; - if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) { - printk("sysv_count_free_blocks: new block %d is not in data zone\n",block); - break; - } - if (!(bh = sv_bread(sb, sb->s_dev, block))) { - printk("sysv_count_free_blocks: cannot read free-list block\n"); - break; - } - bh_data = bh->b_data; - switch (sb->sv_type) { - case FSTYPE_XENIX: - flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree; - flc_blocks = &((struct xenix_freelist_chunk *) bh_data)->fl_free[0]; - break; - case FSTYPE_SYSV4: - flc_count = &((struct sysv4_freelist_chunk *) bh_data)->fl_nfree; - flc_blocks = &((struct sysv4_freelist_chunk *) bh_data)->fl_free[0]; - break; - case FSTYPE_SYSV2: - flc_count = &((struct sysv2_freelist_chunk *) bh_data)->fl_nfree; - flc_blocks = &((struct sysv2_freelist_chunk *) bh_data)->fl_free[0]; - break; - case FSTYPE_COH: - flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree; - flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0]; - break; - default: panic("sysv_count_free_blocks: invalid fs type\n"); - } - if (*flc_count > sb->sv_flc_size) { - printk("sysv_count_free_blocks: free-list block with >flc_size entries\n"); - brelse(bh); - break; - } - if (*flc_count == 0) { /* Applies only to Coherent FS */ - brelse(bh); - break; - } - for (i = *flc_count ; /* i > 0 */ ; ) { - block = flc_blocks[--i]; - if (sb->sv_convert) - block = from_coh_ulong(block); - if (block == 0) /* block 0 terminates list */ - break; - count++; - if (i == 0) - break; - } - /* block = flc_blocks[0], the last block continues the free list */ + block = fs32_to_cpu(sb, block); + if (bh) brelse(bh); - if (block == 0) /* Applies only to Xenix FS and SystemV FS */ - break; - } - done: ; - } - old_count = *sb->sv_sb_total_free_blocks; - if (sb->sv_convert) - old_count = from_coh_ulong(old_count); - if (count != old_count) { - printk("sysv_count_free_blocks: free block count was %d, correcting to %d\n",old_count,count); - if (!(sb->s_flags & MS_RDONLY)) { - *sb->sv_sb_total_free_blocks = (sb->sv_convert ? to_coh_ulong(count) : count); - mark_buffer_dirty(sb->sv_bh2); /* super-block has been modified */ - sb->s_dirt = 1; /* and needs time stamp */ - } + + if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) + goto Einval; + block += sb->sv_block_base; + bh = bread(sb->s_dev, block, sb->s_blocksize); + if (!bh) + goto Eio; + n = fs16_to_cpu(sb, *(u16*)bh->b_data); + blocks = get_chunk(sb, bh); } + if (bh) + brelse(bh); + if (count != sb_count) + goto Ecount; +done: unlock_super(sb); return count; -#else - int count; - count = *sb->sv_sb_total_free_blocks; - if (sb->sv_convert) - count = from_coh_ulong(count); - return count; -#endif +Einval: + printk("sysv_count_free_blocks: new block %d is not in data zone\n", + block); + goto trust_sb; +Eio: + printk("sysv_count_free_blocks: cannot read free-list block\n"); + goto trust_sb; +E2big: + printk("sysv_count_free_blocks: >flc_size entries in free-list block\n"); + if (bh) + brelse(bh); +trust_sb: + count = sb_count; + goto done; +Ecount: + printk("sysv_count_free_blocks: free block count was %d, " + "correcting to %d\n", sb_count, count); + if (!(sb->s_flags & MS_RDONLY)) { + *sb->sv_free_blocks = cpu_to_fs32(sb, count); + dirty_sb(sb); + } + goto done; } - diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c index 5cdf5c605da3..5bff91f6c83b 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c @@ -13,63 +13,356 @@ * SystemV/Coherent directory handling functions */ -#include <linux/errno.h> #include <linux/fs.h> #include <linux/sysv_fs.h> -#include <linux/stat.h> -#include <linux/string.h> +#include <linux/pagemap.h> static int sysv_readdir(struct file *, void *, filldir_t); struct file_operations sysv_dir_operations = { read: generic_read_dir, readdir: sysv_readdir, - fsync: file_fsync, + fsync: sysv_sync_file, }; +static inline void dir_put_page(struct page *page) +{ + kunmap(page); + page_cache_release(page); +} + +static inline unsigned long dir_pages(struct inode *inode) +{ + return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; +} + +static int dir_commit_chunk(struct page *page, unsigned from, unsigned to) +{ + struct inode *dir = (struct inode *)page->mapping->host; + int err = 0; + page->mapping->a_ops->commit_write(NULL, page, from, to); + if (IS_SYNC(dir)) + err = waitfor_one_page(page); + return err; +} + +static struct page * dir_get_page(struct inode *dir, unsigned long n) +{ + struct address_space *mapping = dir->i_mapping; + struct page *page = read_cache_page(mapping, n, + (filler_t*)mapping->a_ops->readpage, NULL); + if (!IS_ERR(page)) { + wait_on_page(page); + kmap(page); + if (!Page_Uptodate(page)) + goto fail; + } + return page; + +fail: + dir_put_page(page); + return ERR_PTR(-EIO); +} + static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir) { + unsigned long pos = filp->f_pos; struct inode *inode = filp->f_dentry->d_inode; - struct super_block * sb = inode->i_sb; - unsigned int offset,i; - struct buffer_head * bh; - char* bh_data; - struct sysv_dir_entry * de, sde; - - if ((unsigned long)(filp->f_pos) % SYSV_DIRSIZE) - return -EBADF; - while (filp->f_pos < inode->i_size) { - offset = filp->f_pos & sb->sv_block_size_1; - bh = sysv_file_bread(inode, filp->f_pos >> sb->sv_block_size_bits, 0); - if (!bh) { - filp->f_pos += sb->sv_block_size - offset; + struct super_block *sb = inode->i_sb; + unsigned offset = pos & ~PAGE_CACHE_MASK; + unsigned long n = pos >> PAGE_CACHE_SHIFT; + unsigned long npages = dir_pages(inode); + + pos = (pos + SYSV_DIRSIZE-1) & ~(SYSV_DIRSIZE-1); + if (pos >= inode->i_size) + goto done; + + for ( ; n < npages; n++, offset = 0) { + char *kaddr, *limit; + struct sysv_dir_entry *de; + struct page *page = dir_get_page(inode, n); + + if (IS_ERR(page)) + continue; + kaddr = (char *)page_address(page); + de = (struct sysv_dir_entry *)(kaddr+offset); + limit = kaddr + PAGE_CACHE_SIZE - SYSV_DIRSIZE; + for ( ;(char*)de <= limit; de++) { + char *name = de->name; + int over; + + if (!de->inode) + continue; + + offset = (char *)de - kaddr; + + over = filldir(dirent, name, strnlen(name,SYSV_NAMELEN), + (n<<PAGE_CACHE_SHIFT) | offset, + fs16_to_cpu(sb, de->inode), DT_UNKNOWN); + if (over) { + dir_put_page(page); + goto done; + } + } + dir_put_page(page); + } + +done: + filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; + UPDATE_ATIME(inode); + return 0; +} + +/* compare strings: name[0..len-1] (not zero-terminated) and + * buffer[0..] (filled with zeroes up to buffer[0..maxlen-1]) + */ +static inline int namecompare(int len, int maxlen, + const char * name, const char * buffer) +{ + if (len < maxlen && buffer[len]) + return 0; + return !memcmp(name, buffer, len); +} + +/* + * sysv_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + */ +struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_page) +{ + const char * name = dentry->d_name.name; + int namelen = dentry->d_name.len; + struct inode * dir = dentry->d_parent->d_inode; + unsigned long n; + unsigned long npages = dir_pages(dir); + struct page *page = NULL; + struct sysv_dir_entry *de; + + *res_page = NULL; + + for (n = 0; n < npages; n++) { + char *kaddr; + page = dir_get_page(dir, n); + if (IS_ERR(page)) continue; + + kaddr = (char*)page_address(page); + de = (struct sysv_dir_entry *) kaddr; + kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE; + for ( ; (char *) de <= kaddr ; de++) { + if (!de->inode) + continue; + if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) + goto found; } - bh_data = bh->b_data; - while (offset < sb->sv_block_size && filp->f_pos < inode->i_size) { - de = (struct sysv_dir_entry *) (offset + bh_data); - if (de->inode) { - /* Copy the directory entry first, because the directory - * might be modified while we sleep in filldir()... - */ - memcpy(&sde, de, sizeof(struct sysv_dir_entry)); - - if (sde.inode > inode->i_sb->sv_ninodes) - printk("sysv_readdir: Bad inode number on dev " - "%s, ino %ld, offset 0x%04lx: %d is out of range\n", - kdevname(inode->i_dev), - inode->i_ino, (off_t) filp->f_pos, sde.inode); - - i = strnlen(sde.name, SYSV_NAMELEN); - if (filldir(dirent, sde.name, i, filp->f_pos, sde.inode, DT_UNKNOWN) < 0) { - brelse(bh); - return 0; - } + dir_put_page(page); + } + return NULL; + +found: + *res_page = page; + return de; +} + +int sysv_add_link(struct dentry *dentry, struct inode *inode) +{ + struct inode *dir = dentry->d_parent->d_inode; + const char * name = dentry->d_name.name; + int namelen = dentry->d_name.len; + struct page *page = NULL; + struct sysv_dir_entry * de; + unsigned long npages = dir_pages(dir); + unsigned long n; + char *kaddr; + unsigned from, to; + int err; + + /* We take care of directory expansion in the same loop */ + for (n = 0; n <= npages; n++) { + page = dir_get_page(dir, n); + err = PTR_ERR(page); + if (IS_ERR(page)) + goto out; + kaddr = (char*)page_address(page); + de = (struct sysv_dir_entry *)kaddr; + kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE; + while ((char *)de <= kaddr) { + if (!de->inode) + goto got_it; + err = -EEXIST; + if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) + goto out_page; + de++; + } + dir_put_page(page); + } + BUG(); + return -EINVAL; + +got_it: + from = (char*)de - (char*)page_address(page); + to = from + SYSV_DIRSIZE; + lock_page(page); + err = page->mapping->a_ops->prepare_write(NULL, page, from, to); + if (err) + goto out_unlock; + memcpy (de->name, name, namelen); + memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen); + de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino); + err = dir_commit_chunk(page, from, to); + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + mark_inode_dirty(dir); +out_unlock: + UnlockPage(page); +out_page: + dir_put_page(page); +out: + return err; +} + +int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page) +{ + struct address_space *mapping = page->mapping; + struct inode *inode = (struct inode*)mapping->host; + char *kaddr = (char*)page_address(page); + unsigned from = (char*)de - kaddr; + unsigned to = from + SYSV_DIRSIZE; + int err; + + lock_page(page); + err = mapping->a_ops->prepare_write(NULL, page, from, to); + if (err) + BUG(); + de->inode = 0; + err = dir_commit_chunk(page, from, to); + UnlockPage(page); + dir_put_page(page); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + mark_inode_dirty(inode); + return err; +} + +int sysv_make_empty(struct inode *inode, struct inode *dir) +{ + struct address_space *mapping = inode->i_mapping; + struct page *page = grab_cache_page(mapping, 0); + struct sysv_dir_entry * de; + char *base; + int err; + + if (!page) + return -ENOMEM; + err = mapping->a_ops->prepare_write(NULL, page, 0, 2 * SYSV_DIRSIZE); + if (err) + goto fail; + + base = (char*)page_address(page); + memset(base, 0, PAGE_CACHE_SIZE); + + de = (struct sysv_dir_entry *) base; + de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino); + strcpy(de->name,"."); + de++; + de->inode = cpu_to_fs16(inode->i_sb, dir->i_ino); + strcpy(de->name,".."); + + err = dir_commit_chunk(page, 0, 2 * SYSV_DIRSIZE); +fail: + UnlockPage(page); + page_cache_release(page); + return err; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +int sysv_empty_dir(struct inode * inode) +{ + struct super_block *sb = inode->i_sb; + struct page *page = NULL; + unsigned long i, npages = dir_pages(inode); + + for (i = 0; i < npages; i++) { + char *kaddr; + struct sysv_dir_entry * de; + page = dir_get_page(inode, i); + + if (IS_ERR(page)) + continue; + + kaddr = (char *)page_address(page); + de = (struct sysv_dir_entry *)kaddr; + kaddr += PAGE_CACHE_SIZE-SYSV_DIRSIZE; + + for ( ;(char *)de <= kaddr; de++) { + if (!de->inode) + continue; + /* check for . and .. */ + if (de->name[0] != '.') + goto not_empty; + if (!de->name[1]) { + if (de->inode == cpu_to_fs16(sb, inode->i_ino)) + continue; + goto not_empty; } - offset += SYSV_DIRSIZE; - filp->f_pos += SYSV_DIRSIZE; + if (de->name[1] != '.' || de->name[2]) + goto not_empty; } - brelse(bh); + dir_put_page(page); } + return 1; + +not_empty: + dir_put_page(page); return 0; } + +/* Releases the page */ +void sysv_set_link(struct sysv_dir_entry *de, struct page *page, + struct inode *inode) +{ + struct inode *dir = (struct inode*)page->mapping->host; + unsigned from = (char *)de-(char*)page_address(page); + unsigned to = from + SYSV_DIRSIZE; + int err; + + lock_page(page); + err = page->mapping->a_ops->prepare_write(NULL, page, from, to); + if (err) + BUG(); + de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino); + err = dir_commit_chunk(page, from, to); + UnlockPage(page); + dir_put_page(page); + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + mark_inode_dirty(dir); +} + +struct sysv_dir_entry * sysv_dotdot (struct inode *dir, struct page **p) +{ + struct page *page = dir_get_page(dir, 0); + struct sysv_dir_entry *de = NULL; + + if (!IS_ERR(page)) { + de = (struct sysv_dir_entry*) page_address(page) + 1; + *p = page; + } + return de; +} + +ino_t sysv_inode_by_name(struct dentry *dentry) +{ + struct page *page; + struct sysv_dir_entry *de = sysv_find_entry (dentry, &page); + ino_t res = 0; + + if (de) { + res = fs16_to_cpu(dentry->d_sb, de->inode); + dir_put_page(page); + } + return res; +} diff --git a/fs/sysv/file.c b/fs/sysv/file.c index d68967b19c02..f602afb68519 100644 --- a/fs/sysv/file.c +++ b/fs/sysv/file.c @@ -31,3 +31,17 @@ struct inode_operations sysv_file_inode_operations = { truncate: sysv_truncate, setattr: sysv_notify_change, }; + +int sysv_sync_file(struct file * file, struct dentry *dentry, int datasync) +{ + struct inode *inode = dentry->d_inode; + int err = fsync_inode_buffers(inode); + + if (!(inode->i_state & I_DIRTY)) + return err; + if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) + return err; + + err |= sysv_sync_inode(inode); + return err ? -EIO : 0; +} diff --git a/fs/sysv/fsync.c b/fs/sysv/fsync.c deleted file mode 100644 index 091605cd1732..000000000000 --- a/fs/sysv/fsync.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * linux/fs/sysv/fsync.c - * - * minix/fsync.c - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk) - * - * coh/fsync.c - * Copyright (C) 1993 Pascal Haible, Bruno Haible - * - * sysv/fsync.c - * Copyright (C) 1993 Bruno Haible - * - * SystemV/Coherent fsync primitive - */ - -#include <linux/errno.h> -#include <linux/stat.h> -#include <linux/fs.h> -#include <linux/sysv_fs.h> -#include <linux/smp_lock.h> - - -/* return values: 0 means OK/done, 1 means redo, -1 means I/O error. */ - -/* Sync one block. The block number is - * from_coh_ulong(*blockp) if convert=1, *blockp if convert=0. - */ -static int sync_block (struct inode * inode, u32 *blockp, int convert, int wait) -{ - struct buffer_head * bh; - u32 tmp, block; - struct super_block * sb; - - block = tmp = *blockp; - if (convert) - block = from_coh_ulong(block); - if (!block) - return 0; - sb = inode->i_sb; - bh = sv_get_hash_table(sb, inode->i_dev, block); - if (!bh) - return 0; - if (*blockp != tmp) { - brelse (bh); - return 1; - } - if (wait && buffer_req(bh) && !buffer_uptodate(bh)) { - brelse(bh); - return -1; - } - if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) { - brelse(bh); - return 0; - } - ll_rw_block(WRITE, 1, &bh); - atomic_dec(&bh->b_count); - return 0; -} - -/* Sync one block full of indirect pointers and read it because we'll need it. */ -static int sync_iblock (struct inode * inode, u32 * iblockp, int convert, - struct buffer_head * *bh, int wait) -{ - int rc; - u32 tmp, block; - - *bh = NULL; - block = tmp = *iblockp; - if (convert) - block = from_coh_ulong(block); - if (!block) - return 0; - rc = sync_block (inode, iblockp, convert, wait); - if (rc) - return rc; - *bh = sv_bread(inode->i_sb, inode->i_dev, block); - if (tmp != *iblockp) { - brelse(*bh); - *bh = NULL; - return 1; - } - if (!*bh) - return -1; - return 0; -} - - -static int sync_direct(struct inode *inode, int wait) -{ - int i; - int rc, err = 0; - - for (i = 0; i < 10; i++) { - rc = sync_block (inode, inode->u.sysv_i.i_data + i, 0, wait); - if (rc > 0) - break; - if (rc) - err = rc; - } - return err; -} - -static int sync_indirect(struct inode *inode, u32 *iblockp, int convert, int wait) -{ - int i; - struct buffer_head * ind_bh; - int rc, err = 0; - struct super_block * sb; - - rc = sync_iblock (inode, iblockp, convert, &ind_bh, wait); - if (rc || !ind_bh) - return rc; - - sb = inode->i_sb; - for (i = 0; i < sb->sv_ind_per_block; i++) { - rc = sync_block (inode, - ((u32 *) ind_bh->b_data) + i, sb->sv_convert, - wait); - if (rc > 0) - break; - if (rc) - err = rc; - } - brelse(ind_bh); - return err; -} - -static int sync_dindirect(struct inode *inode, u32 *diblockp, int convert, - int wait) -{ - int i; - struct buffer_head * dind_bh; - int rc, err = 0; - struct super_block * sb; - - rc = sync_iblock (inode, diblockp, convert, &dind_bh, wait); - if (rc || !dind_bh) - return rc; - - sb = inode->i_sb; - for (i = 0; i < sb->sv_ind_per_block; i++) { - rc = sync_indirect (inode, - ((u32 *) dind_bh->b_data) + i, sb->sv_convert, - wait); - if (rc > 0) - break; - if (rc) - err = rc; - } - brelse(dind_bh); - return err; -} - -static int sync_tindirect(struct inode *inode, u32 *tiblockp, int convert, - int wait) -{ - int i; - struct buffer_head * tind_bh; - int rc, err = 0; - struct super_block * sb; - - rc = sync_iblock (inode, tiblockp, convert, &tind_bh, wait); - if (rc || !tind_bh) - return rc; - - sb = inode->i_sb; - for (i = 0; i < sb->sv_ind_per_block; i++) { - rc = sync_dindirect (inode, - ((u32 *) tind_bh->b_data) + i, sb->sv_convert, - wait); - if (rc > 0) - break; - if (rc) - err = rc; - } - brelse(tind_bh); - return err; -} - -int sysv_sync_file(struct file * file, struct dentry *dentry, int datasync) -{ - int wait, err = 0; - struct inode *inode = dentry->d_inode; - - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - S_ISLNK(inode->i_mode))) - return -EINVAL; - - lock_kernel(); - for (wait=0; wait<=1; wait++) { - err |= sync_direct(inode, wait); - err |= sync_indirect(inode, inode->u.sysv_i.i_data+10, 0, wait); - err |= sync_dindirect(inode, inode->u.sysv_i.i_data+11, 0, wait); - err |= sync_tindirect(inode, inode->u.sysv_i.i_data+12, 0, wait); - } - err |= sysv_sync_inode (inode); - unlock_kernel(); - return (err < 0) ? -EIO : 0; -} diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c index 7709ade8d904..e2c8f3ce3925 100644 --- a/fs/sysv/ialloc.c +++ b/fs/sysv/ialloc.c @@ -19,7 +19,6 @@ * This file contains code for allocating/freeing inodes. */ -#include <linux/sched.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/sysv_fs.h> @@ -35,7 +34,8 @@ /* An inode on disk is considered free if both i_mode == 0 and i_nlink == 0. */ /* return &sb->sv_sb_fic_inodes[i] = &sbd->s_inode[i]; */ -static inline sysv_ino_t * sv_sb_fic_inode (struct super_block * sb, unsigned int i) +static inline sysv_ino_t * +sv_sb_fic_inode(struct super_block * sb, unsigned int i) { if (sb->sv_bh1 == sb->sv_bh2) return &sb->sv_sb_fic_inodes[i]; @@ -49,12 +49,55 @@ static inline sysv_ino_t * sv_sb_fic_inode (struct super_block * sb, unsigned in } } +struct sysv_inode * +sysv_raw_inode(struct super_block *sb, unsigned ino, struct buffer_head **bh) +{ + struct sysv_inode *res; + int block = sb->sv_firstinodezone + sb->sv_block_base; + block += (ino-1) >> sb->sv_inodes_per_block_bits; + *bh = bread(sb->s_dev, block, sb->s_blocksize); + if (!*bh) + return NULL; + res = (struct sysv_inode *) (*bh)->b_data; + return res + ((ino-1) & sb->sv_inodes_per_block_1); +} + +static int refill_free_cache(struct super_block *sb) +{ + struct buffer_head * bh; + struct sysv_inode * raw_inode; + int i = 0, ino; + + ino = SYSV_ROOT_INO+1; + raw_inode = sysv_raw_inode(sb, ino, &bh); + if (!raw_inode) + goto out; + while (ino <= sb->sv_ninodes) { + if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) { + *sv_sb_fic_inode(sb,i++) = cpu_to_fs16(sb, ino); + if (i == sb->sv_fic_size) + break; + } + if ((ino++ & sb->sv_inodes_per_block_1) == 0) { + brelse(bh); + raw_inode = sysv_raw_inode(sb, ino, &bh); + if (!raw_inode) + goto out; + } else + raw_inode++; + } + brelse(bh); +out: + return i; +} + void sysv_free_inode(struct inode * inode) { struct super_block * sb; unsigned int ino; struct buffer_head * bh; struct sysv_inode * raw_inode; + unsigned count; sb = inode->i_sb; ino = inode->i_ino; @@ -62,137 +105,119 @@ void sysv_free_inode(struct inode * inode) printk("sysv_free_inode: inode 0,1,2 or nonexistent inode\n"); return; } - if (!(bh = sv_bread(sb, inode->i_dev, sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits)))) { + raw_inode = sysv_raw_inode(sb, ino, &bh); + clear_inode(inode); + if (!raw_inode) { printk("sysv_free_inode: unable to read inode block on device " - "%s\n", kdevname(inode->i_dev)); - clear_inode(inode); + "%s\n", bdevname(inode->i_dev)); return; } - raw_inode = (struct sysv_inode *) bh->b_data + ((ino-1) & sb->sv_inodes_per_block_1); - clear_inode(inode); lock_super(sb); - if (*sb->sv_sb_fic_count < sb->sv_fic_size) - *sv_sb_fic_inode(sb,(*sb->sv_sb_fic_count)++) = ino; - (*sb->sv_sb_total_free_inodes)++; - mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */ - if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2); - sb->s_dirt = 1; /* and needs time stamp */ + count = fs16_to_cpu(sb, *sb->sv_sb_fic_count); + if (count < sb->sv_fic_size) { + *sv_sb_fic_inode(sb,count++) = cpu_to_fs16(sb, ino); + *sb->sv_sb_fic_count = cpu_to_fs16(sb, count); + } + fs16_add(sb, sb->sv_sb_total_free_inodes, 1); + dirty_sb(sb); memset(raw_inode, 0, sizeof(struct sysv_inode)); mark_buffer_dirty(bh); unlock_super(sb); brelse(bh); } -struct inode * sysv_new_inode(const struct inode * dir) +struct inode * sysv_new_inode(const struct inode * dir, mode_t mode) { struct inode * inode; struct super_block * sb; - struct buffer_head * bh; - struct sysv_inode * raw_inode; - int i,j,ino,block; + u16 ino; + unsigned count; - if (!dir) - return NULL; sb = dir->i_sb; inode = new_inode(sb); if (!inode) return NULL; - lock_super(sb); /* protect against task switches */ - if ((*sb->sv_sb_fic_count == 0) - || (*sv_sb_fic_inode(sb,(*sb->sv_sb_fic_count)-1) == 0) /* Applies only to SystemV2 FS */ - ) { - /* Rebuild cache of free inodes: */ - /* i : index into cache slot being filled */ - /* ino : inode we are trying */ - /* block : firstinodezone + (ino-1)/inodes_per_block */ - /* j : (ino-1)%inodes_per_block */ - /* bh : buffer for block */ - /* raw_inode : pointer to inode ino in the block */ - for (i = 0, ino = SYSV_ROOT_INO+1, block = sb->sv_firstinodezone, j = SYSV_ROOT_INO ; i < sb->sv_fic_size && block < sb->sv_firstdatazone ; block++, j = 0) { - if (!(bh = sv_bread(sb, sb->s_dev, block))) { - printk("sysv_new_inode: unable to read inode table\n"); - break; /* go with what we've got */ - /* FIXME: Perhaps try the next block? */ - } - raw_inode = (struct sysv_inode *) bh->b_data + j; - for (; j < sb->sv_inodes_per_block && i < sb->sv_fic_size; ino++, j++, raw_inode++) { - if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) - *sv_sb_fic_inode(sb,i++) = ino; - } - brelse(bh); - } - if (i == 0) { + lock_super(sb); + count = fs16_to_cpu(sb, *sb->sv_sb_fic_count); + if (count == 0 || (*sv_sb_fic_inode(sb,count-1) == 0)) { + count = refill_free_cache(sb); + if (count == 0) { iput(inode); unlock_super(sb); - return NULL; /* no inodes available */ + return NULL; } - *sb->sv_sb_fic_count = i; } - /* Now *sb->sv_sb_fic_count > 0. */ - ino = *sv_sb_fic_inode(sb,--(*sb->sv_sb_fic_count)); - mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */ - if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2); - sb->s_dirt = 1; /* and needs time stamp */ + /* Now count > 0. */ + ino = *sv_sb_fic_inode(sb,--count); + *sb->sv_sb_fic_count = cpu_to_fs16(sb, count); + fs16_add(sb, sb->sv_sb_total_free_inodes, -1); + dirty_sb(sb); inode->i_uid = current->fsuid; inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; - inode->i_ino = ino; + inode->i_ino = fs16_to_cpu(sb, ino); inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_blocks = inode->i_blksize = 0; insert_inode_hash(inode); mark_inode_dirty(inode); - /* Change directory entry: */ - inode->i_mode = 0; /* for sysv_write_inode() */ + inode->i_mode = mode; /* for sysv_write_inode() */ sysv_write_inode(inode, 0); /* ensure inode not allocated again */ /* FIXME: caller may call this too. */ mark_inode_dirty(inode); /* cleared by sysv_write_inode() */ /* That's it. */ - (*sb->sv_sb_total_free_inodes)--; - mark_buffer_dirty(sb->sv_bh2); /* super-block has been modified again */ - sb->s_dirt = 1; /* and needs time stamp again */ unlock_super(sb); return inode; } unsigned long sysv_count_free_inodes(struct super_block * sb) { -#if 1 /* test */ struct buffer_head * bh; struct sysv_inode * raw_inode; - int j,block,count; + int ino, count, sb_count; + + lock_super(sb); + + sb_count = fs16_to_cpu(sb, *sb->sv_sb_total_free_inodes); + + if (0) + goto trust_sb; /* this causes a lot of disk traffic ... */ count = 0; - lock_super(sb); - /* i : index into cache slot being filled */ - /* ino : inode we are trying */ - /* block : firstinodezone + (ino-1)/inodes_per_block */ - /* j : (ino-1)%inodes_per_block */ - /* bh : buffer for block */ - /* raw_inode : pointer to inode ino in the block */ - for (block = sb->sv_firstinodezone, j = SYSV_ROOT_INO ; block < sb->sv_firstdatazone ; block++, j = 0) { - if (!(bh = sv_bread(sb, sb->s_dev, block))) { - printk("sysv_count_free_inodes: unable to read inode table\n"); - break; /* go with what we've got */ - /* FIXME: Perhaps try the next block? */ - } - raw_inode = (struct sysv_inode *) bh->b_data + j; - for (; j < sb->sv_inodes_per_block ; j++, raw_inode++) - if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) - count++; - brelse(bh); - } - if (count != *sb->sv_sb_total_free_inodes) { - printk("sysv_count_free_inodes: free inode count was %d, correcting to %d\n",(short)(*sb->sv_sb_total_free_inodes),count); - if (!(sb->s_flags & MS_RDONLY)) { - *sb->sv_sb_total_free_inodes = count; - mark_buffer_dirty(sb->sv_bh2); /* super-block has been modified */ - sb->s_dirt = 1; /* and needs time stamp */ - } + ino = SYSV_ROOT_INO+1; + raw_inode = sysv_raw_inode(sb, ino, &bh); + if (!raw_inode) + goto Eio; + while (ino <= sb->sv_ninodes) { + if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) + count++; + if ((ino++ & sb->sv_inodes_per_block_1) == 0) { + brelse(bh); + raw_inode = sysv_raw_inode(sb, ino, &bh); + if (!raw_inode) + goto Eio; + } else + raw_inode++; } + brelse(bh); + if (count != sb_count) + goto Einval; +out: unlock_super(sb); return count; -#else - return *sb->sv_sb_total_free_inodes; -#endif -} +Einval: + printk("sysv_count_free_inodes: " + "free inode count was %d, correcting to %d\n", + sb_count, count); + if (!(sb->s_flags & MS_RDONLY)) { + *sb->sv_sb_total_free_inodes = cpu_to_fs16(sb, count); + dirty_sb(sb); + } + goto out; + +Eio: + printk("sysv_count_free_inodes: unable to read inode table\n"); +trust_sb: + count = sb_count; + goto out; +} diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 786fad71a881..1a75d66897b7 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -21,499 +21,13 @@ * the superblock. */ -#include <linux/config.h> -#include <linux/module.h> - -#include <linux/sched.h> -#include <linux/kernel.h> #include <linux/fs.h> #include <linux/sysv_fs.h> -#include <linux/stat.h> -#include <linux/string.h> #include <linux/locks.h> -#include <linux/init.h> #include <linux/smp_lock.h> #include <linux/highuid.h> #include <asm/byteorder.h> -#include <asm/uaccess.h> - -#if 0 -void sysv_print_inode(struct inode * inode) -{ - printk("ino %lu mode 0%6.6o lk %d uid %d gid %d" - " sz %lu blks %lu cnt %u\n", - inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid, - inode->i_gid, inode->i_size, inode->i_blocks, - atomic_read(&inode->i_count)); - printk(" db <0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx" - " 0x%lx 0x%lx>\n", - inode->u.sysv_i.i_data[0], inode->u.sysv_i.i_data[1], - inode->u.sysv_i.i_data[2], inode->u.sysv_i.i_data[3], - inode->u.sysv_i.i_data[4], inode->u.sysv_i.i_data[5], - inode->u.sysv_i.i_data[6], inode->u.sysv_i.i_data[7], - inode->u.sysv_i.i_data[8], inode->u.sysv_i.i_data[9]); - printk(" ib <0x%lx 0x%lx 0x%lx>\n", - inode->u.sysv_i.i_data[10], - inode->u.sysv_i.i_data[11], - inode->u.sysv_i.i_data[12]); -} -#endif - -static void sysv_delete_inode(struct inode *inode) -{ - lock_kernel(); - inode->i_size = 0; - sysv_truncate(inode); - sysv_free_inode(inode); - unlock_kernel(); -} - -static void sysv_put_super(struct super_block *); -static void sysv_write_super(struct super_block *); -static void sysv_read_inode(struct inode *); -static int sysv_statfs(struct super_block *, struct statfs *); - -static struct super_operations sysv_sops = { - read_inode: sysv_read_inode, - write_inode: sysv_write_inode, - delete_inode: sysv_delete_inode, - put_super: sysv_put_super, - write_super: sysv_write_super, - statfs: sysv_statfs, -}; - -/* The following functions try to recognize specific filesystems. - * We recognize: - * - Xenix FS by its magic number. - * - SystemV FS by its magic number. - * - Coherent FS by its funny fname/fpack field. - * We discriminate among SystemV4 and SystemV2 FS by the assumption that - * the time stamp is not < 01-01-1980. - */ - -static void detected_bs (u_char type, struct super_block *sb) -{ - u_char n_bits = type+8; - int bsize = 1 << n_bits; - int bsize_4 = bsize >> 2; - - sb->sv_block_size = bsize; - sb->sv_block_size_1 = bsize-1; - sb->sv_block_size_bits = n_bits; - sb->sv_block_size_dec_bits = (bsize==512) ? 1 : 0; - sb->sv_block_size_inc_bits = (bsize==2048) ? 1 : 0; - sb->sv_inodes_per_block = bsize >> 6; - sb->sv_inodes_per_block_1 = (bsize >> 6)-1; - sb->sv_inodes_per_block_bits = n_bits-6; - sb->sv_toobig_block = 10 + - (sb->sv_ind_per_block = bsize_4) + - (sb->sv_ind_per_block_2 = bsize_4*bsize_4) + - (sb->sv_ind_per_block_3 = bsize_4*bsize_4*bsize_4); - sb->sv_ind_per_block_1 = bsize_4-1; - sb->sv_ind_per_block_2_1 = bsize_4*bsize_4-1; - sb->sv_ind_per_block_2_bits = 2 * - (sb->sv_ind_per_block_bits = n_bits-2); - sb->sv_ind_per_block_block_size_1 = bsize_4*bsize-1; - sb->sv_ind_per_block_block_size_bits = 2*n_bits-2; - sb->sv_ind_per_block_2_block_size_1 = bsize_4*bsize_4*bsize-1; - sb->sv_ind_per_block_2_block_size_bits = 3*n_bits-4; - sb->sv_ind0_size = 10 * bsize; - sb->sv_ind1_size = (10 + bsize_4)* bsize; - sb->sv_ind2_size = (10 + bsize_4 + bsize_4*bsize_4) * bsize; -} - -static const char* detect_xenix (struct super_block *sb, struct buffer_head *bh) -{ - struct xenix_super_block * sbd; - - sbd = (struct xenix_super_block *) bh->b_data; - if (sbd->s_magic != 0x2b5544) - return NULL; - if (sbd->s_type > 2 || sbd->s_type < 1) - return NULL; - detected_bs(sbd->s_type, sb); - sb->sv_type = FSTYPE_XENIX; - return "Xenix"; -} -static struct super_block * detected_xenix (struct super_block *sb, struct buffer_head *bh1, struct buffer_head *bh2) -{ - struct xenix_super_block * sbd1; - struct xenix_super_block * sbd2; - - if (sb->sv_block_size >= BLOCK_SIZE) - /* block size >= 1024, so bh1 = bh2 */ - sbd1 = sbd2 = (struct xenix_super_block *) bh1->b_data; - else { - /* block size = 512, so bh1 != bh2 */ - sbd1 = (struct xenix_super_block *) bh1->b_data; - sbd2 = (struct xenix_super_block *) (bh2->b_data - BLOCK_SIZE/2); - /* sanity check */ - if (sbd2->s_magic != 0x2b5544) - return NULL; - } - - sb->sv_convert = 0; - sb->sv_kludge_symlinks = 1; - sb->sv_truncate = 1; - sb->sv_link_max = XENIX_LINK_MAX; - sb->sv_fic_size = XENIX_NICINOD; - sb->sv_flc_size = XENIX_NICFREE; - sb->sv_bh1 = bh1; - sb->sv_bh2 = bh2; - sb->sv_sbd1 = (char *) sbd1; - sb->sv_sbd2 = (char *) sbd2; - sb->sv_sb_fic_count = &sbd1->s_ninode; - sb->sv_sb_fic_inodes = &sbd1->s_inode[0]; - sb->sv_sb_total_free_inodes = &sbd2->s_tinode; - sb->sv_sb_flc_count = &sbd1->s_nfree; - sb->sv_sb_flc_blocks = &sbd1->s_free[0]; - sb->sv_sb_total_free_blocks = &sbd2->s_tfree; - sb->sv_sb_time = &sbd2->s_time; - sb->sv_firstinodezone = 2; - sb->sv_firstdatazone = sbd1->s_isize; - sb->sv_nzones = sbd1->s_fsize; - sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone; - return sb; -} - -static const char* detect_sysv4 (struct super_block *sb, struct buffer_head *bh) -{ - struct sysv4_super_block * sbd; - - sbd = (struct sysv4_super_block *) (bh->b_data + BLOCK_SIZE/2); - if (sbd->s_magic != 0xfd187e20) - return NULL; - if (sbd->s_time < 315532800) /* this is likely to happen on SystemV2 FS */ - return NULL; - if ((sbd->s_type > 3 || sbd->s_type < 1) && (sbd->s_type > 0x30 || sbd->s_type < 0x10)) - return NULL; - - /* On Interactive Unix (ISC) Version 4.0/3.x s_type field = 0x10, - 0x20 or 0x30 indicates that symbolic links and the 14-character - filename limit is gone. Due to lack of information about this - feature read-only mode seems to be a reasonable approach... -KGB */ - - if (sbd->s_type >= 0x10) { - printk("SysV FS: can't handle long file names on %s, " - "forcing read-only mode.\n", kdevname(sb->s_dev)); - sb->s_flags |= MS_RDONLY; - } - - detected_bs(sbd->s_type >= 0x10 ? (sbd->s_type >> 4) : sbd->s_type, sb); - sb->sv_type = FSTYPE_SYSV4; - return "SystemV"; -} - -static struct super_block * detected_sysv4 (struct super_block *sb, struct buffer_head *bh) -{ - struct sysv4_super_block * sbd; - - if (sb->sv_block_size >= BLOCK_SIZE) - sbd = (struct sysv4_super_block *) (bh->b_data + BLOCK_SIZE/2); - else { - sbd = (struct sysv4_super_block *) bh->b_data; - /* sanity check */ - if (sbd->s_magic != 0xfd187e20) - return NULL; - if (sbd->s_time < 315532800) - return NULL; - } - - sb->sv_convert = 0; - sb->sv_kludge_symlinks = 0; /* ?? */ - sb->sv_truncate = 1; - sb->sv_link_max = SYSV_LINK_MAX; - sb->sv_fic_size = SYSV_NICINOD; - sb->sv_flc_size = SYSV_NICFREE; - sb->sv_bh1 = bh; - sb->sv_bh2 = bh; - sb->sv_sbd1 = (char *) sbd; - sb->sv_sbd2 = (char *) sbd; - sb->sv_sb_fic_count = &sbd->s_ninode; - sb->sv_sb_fic_inodes = &sbd->s_inode[0]; - sb->sv_sb_total_free_inodes = &sbd->s_tinode; - sb->sv_sb_flc_count = &sbd->s_nfree; - sb->sv_sb_flc_blocks = &sbd->s_free[0]; - sb->sv_sb_total_free_blocks = &sbd->s_tfree; - sb->sv_sb_time = &sbd->s_time; - sb->sv_sb_state = &sbd->s_state; - sb->sv_firstinodezone = 2; - sb->sv_firstdatazone = sbd->s_isize; - sb->sv_nzones = sbd->s_fsize; - sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone; - return sb; -} - -static const char* detect_sysv2 (struct super_block *sb, struct buffer_head *bh) -{ - struct sysv2_super_block * sbd; - sbd = (struct sysv2_super_block *) (bh->b_data + BLOCK_SIZE/2); - if (sbd->s_magic != 0xfd187e20) - return NULL; - if (sbd->s_time < 315532800) /* this is likely to happen on SystemV4 FS */ - return NULL; - if (sbd->s_type > 3 || sbd->s_type < 1) - return NULL; - detected_bs(sbd->s_type, sb); - sb->sv_type = FSTYPE_SYSV2; - return "SystemV Release 2"; -} -static struct super_block * detected_sysv2 (struct super_block *sb, struct buffer_head *bh) -{ - struct sysv2_super_block * sbd; - - if (sb->sv_block_size >= BLOCK_SIZE) - sbd = (struct sysv2_super_block *) (bh->b_data + BLOCK_SIZE/2); - else { - sbd = (struct sysv2_super_block *) bh->b_data; - /* sanity check */ - if (sbd->s_magic != 0xfd187e20) - return NULL; - if (sbd->s_time < 315532800) - return NULL; - } - - sb->sv_convert = 0; - sb->sv_kludge_symlinks = 0; /* ?? */ - sb->sv_truncate = 1; - sb->sv_link_max = SYSV_LINK_MAX; - sb->sv_fic_size = SYSV_NICINOD; - sb->sv_flc_size = SYSV_NICFREE; - sb->sv_bh1 = bh; - sb->sv_bh2 = bh; - sb->sv_sbd1 = (char *) sbd; - sb->sv_sbd2 = (char *) sbd; - sb->sv_sb_fic_count = &sbd->s_ninode; - sb->sv_sb_fic_inodes = &sbd->s_inode[0]; - sb->sv_sb_total_free_inodes = &sbd->s_tinode; - sb->sv_sb_flc_count = &sbd->s_nfree; - sb->sv_sb_flc_blocks = &sbd->s_free[0]; - sb->sv_sb_total_free_blocks = &sbd->s_tfree; - sb->sv_sb_time = &sbd->s_time; - sb->sv_sb_state = &sbd->s_state; - sb->sv_firstinodezone = 2; - sb->sv_firstdatazone = sbd->s_isize; - sb->sv_nzones = sbd->s_fsize; - sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone; - return sb; -} - -static const char* detect_coherent (struct super_block *sb, struct buffer_head *bh) -{ - struct coh_super_block * sbd; - - sbd = (struct coh_super_block *) (bh->b_data + BLOCK_SIZE/2); - if ((memcmp(sbd->s_fname,"noname",6) && memcmp(sbd->s_fname,"xxxxx ",6)) - || (memcmp(sbd->s_fpack,"nopack",6) && memcmp(sbd->s_fpack,"xxxxx\n",6))) - return NULL; - detected_bs(1, sb); - sb->sv_type = FSTYPE_COH; - return "Coherent"; -} -static struct super_block * detected_coherent (struct super_block *sb, struct buffer_head *bh) -{ - struct coh_super_block * sbd; - - sbd = (struct coh_super_block *) bh->b_data; - /* sanity check */ - if ((memcmp(sbd->s_fname,"noname",6) && memcmp(sbd->s_fname,"xxxxx ",6)) - || (memcmp(sbd->s_fpack,"nopack",6) && memcmp(sbd->s_fpack,"xxxxx\n",6))) - return NULL; - - sb->sv_convert = 1; - sb->sv_kludge_symlinks = 1; - sb->sv_truncate = 1; - sb->sv_link_max = COH_LINK_MAX; - sb->sv_fic_size = COH_NICINOD; - sb->sv_flc_size = COH_NICFREE; - sb->sv_bh1 = bh; - sb->sv_bh2 = bh; - sb->sv_sbd1 = (char *) sbd; - sb->sv_sbd2 = (char *) sbd; - sb->sv_sb_fic_count = &sbd->s_ninode; - sb->sv_sb_fic_inodes = &sbd->s_inode[0]; - sb->sv_sb_total_free_inodes = &sbd->s_tinode; - sb->sv_sb_flc_count = &sbd->s_nfree; - sb->sv_sb_flc_blocks = &sbd->s_free[0]; - sb->sv_sb_total_free_blocks = &sbd->s_tfree; - sb->sv_sb_time = &sbd->s_time; - sb->sv_firstinodezone = 2; - sb->sv_firstdatazone = sbd->s_isize; - sb->sv_nzones = from_coh_ulong(sbd->s_fsize); - sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone; - return sb; -} - -static struct super_block *sysv_read_super(struct super_block *sb, - void *data, int silent) -{ - struct buffer_head *bh; - const char *found; - kdev_t dev = sb->s_dev; - struct inode *root_inode; - unsigned long blocknr; - - if (1024 != sizeof (struct xenix_super_block)) - panic("Xenix FS: bad super-block size"); - if ((512 != sizeof (struct sysv4_super_block)) - || (512 != sizeof (struct sysv2_super_block))) - panic("SystemV FS: bad super-block size"); - if (500 != sizeof (struct coh_super_block)) - panic("Coherent FS: bad super-block size"); - if (64 != sizeof (struct sysv_inode)) - panic("sysv fs: bad i-node size"); - set_blocksize(dev,BLOCK_SIZE); - sb->sv_block_base = 0; - - /* Try to read Xenix superblock */ - if ((bh = bread(dev, 1, BLOCK_SIZE)) != NULL) { - if ((found = detect_xenix(sb,bh)) != NULL) - goto ok; - brelse(bh); - } - if ((bh = bread(dev, 0, BLOCK_SIZE)) != NULL) { - /* Try to recognize SystemV superblock */ - if ((found = detect_sysv4(sb,bh)) != NULL) - goto ok; - if ((found = detect_sysv2(sb,bh)) != NULL) - goto ok; - /* Try to recognize Coherent superblock */ - if ((found = detect_coherent(sb,bh)) != NULL) - goto ok; - brelse(bh); - } - /* Try to recognize SystemV superblock */ - /* Offset by 1 track, i.e. most probably 9, 15, or 18 kilobytes. */ - /* 2kB blocks with offset of 9 and 15 kilobytes are not supported. */ - /* Maybe we should also check the device geometry ? */ - { static int offsets[] = { 9, 15, 18, }; - int i; - for (i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) - if ((bh = bread(dev, offsets[i], BLOCK_SIZE)) != NULL) { - /* Try to recognize SystemV superblock */ - if ((found = detect_sysv4(sb,bh)) != NULL) { - if (sb->sv_block_size>BLOCK_SIZE && (offsets[i] % 2)) - goto bad_shift; - sb->sv_block_base = (offsets[i] << sb->sv_block_size_dec_bits) >> sb->sv_block_size_inc_bits; - goto ok; - } - if ((found = detect_sysv2(sb,bh)) != NULL) { - if (sb->sv_block_size>BLOCK_SIZE && (offsets[i] % 2)) - goto bad_shift; - sb->sv_block_base = (offsets[i] << sb->sv_block_size_dec_bits) >> sb->sv_block_size_inc_bits; - goto ok; - } - brelse(bh); - } - } - bad_shift: - if (!silent) - printk("VFS: unable to read Xenix/SystemV/Coherent superblock on device " - "%s\n", kdevname(dev)); - failed: - return NULL; - - ok: - if (sb->sv_block_size >= BLOCK_SIZE) { - if (sb->sv_block_size != BLOCK_SIZE) { - brelse(bh); - set_blocksize(dev, sb->sv_block_size); - blocknr = (bh->b_blocknr << sb->sv_block_size_dec_bits) >> sb->sv_block_size_inc_bits; - if ((bh = bread(dev, blocknr, sb->sv_block_size)) == NULL) - goto bad_superblock; - } - switch (sb->sv_type) { - case FSTYPE_XENIX: - if (!detected_xenix(sb,bh,bh)) - goto bad_superblock; - break; - case FSTYPE_SYSV4: - if (!detected_sysv4(sb,bh)) - goto bad_superblock; - break; - case FSTYPE_SYSV2: - if (!detected_sysv2(sb,bh)) - goto bad_superblock; - break; - default: goto bad_superblock; - goto superblock_ok; - bad_superblock: - brelse(bh); - printk("SysV FS: cannot read superblock in %d byte mode\n", sb->sv_block_size); - goto failed; - superblock_ok:; - } - } else { - /* Switch to 512 block size. Unfortunately, we have to - release the block bh and read it again. */ - struct buffer_head *bh1, *bh2; - unsigned long blocknr = (bh->b_blocknr << sb->sv_block_size_dec_bits) >> sb->sv_block_size_inc_bits; - - brelse(bh); - set_blocksize(dev,sb->sv_block_size); - bh1 = NULL; bh2 = NULL; - switch (sb->sv_type) { - case FSTYPE_XENIX: - if ((bh1 = bread(dev, blocknr, sb->sv_block_size)) == NULL) - goto bad_superblock2; - if ((bh2 = bread(dev, blocknr+1, sb->sv_block_size)) == NULL) - goto bad_superblock2; - if (!detected_xenix(sb,bh1,bh2)) - goto bad_superblock2; - break; - case FSTYPE_SYSV4: - if ((bh2 = bread(dev, blocknr+1, sb->sv_block_size)) == NULL) - goto bad_superblock2; - if (!detected_sysv4(sb,bh2)) - goto bad_superblock2; - break; - case FSTYPE_SYSV2: - if ((bh2 = bread(dev, blocknr+1, sb->sv_block_size)) == NULL) - goto bad_superblock2; - if (!detected_sysv2(sb,bh2)) - goto bad_superblock2; - break; - case FSTYPE_COH: - if ((bh2 = bread(dev, blocknr+1, sb->sv_block_size)) == NULL) - goto bad_superblock2; - if (!detected_coherent(sb,bh2)) - goto bad_superblock2; - break; - default: - bad_superblock2: - brelse(bh1); - brelse(bh2); - set_blocksize(sb->s_dev,BLOCK_SIZE); - printk("SysV FS: cannot read superblock in 512 byte mode\n"); - goto failed; - } - } - sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone) << sb->sv_inodes_per_block_bits; - if (!silent) - printk("VFS: Found a %s FS (block size = %d) on device %s\n", - found, sb->sv_block_size, kdevname(dev)); - sb->s_magic = SYSV_MAGIC_BASE + sb->sv_type; - /* The buffer code now supports block size 512 as well as 1024. */ - sb->s_blocksize = sb->sv_block_size; - sb->s_blocksize_bits = sb->sv_block_size_bits; - /* set up enough so that it can read an inode */ - sb->s_op = &sysv_sops; - root_inode = iget(sb,SYSV_ROOT_INO); - sb->s_root = d_alloc_root(root_inode); - if (!sb->s_root) { - printk("SysV FS: get root inode failed\n"); - sysv_put_super(sb); - return NULL; - } -#ifndef CONFIG_SYSV_FS_WRITE - sb->s_flags |= MS_RDONLY; -#endif - sb->s_dirt = 1; - /* brelse(bh); resp. brelse(bh1); brelse(bh2); - occurs when the disk is unmounted. */ - return sb; -} /* This is only called on sync() and umount(), when s_dirt=1. */ static void sysv_write_super(struct super_block *sb) @@ -523,15 +37,11 @@ static void sysv_write_super(struct super_block *sb) then attach current time stamp. But if the filesystem was marked clean, keep it clean. */ unsigned long time = CURRENT_TIME; - unsigned long old_time = *sb->sv_sb_time; - if (sb->sv_convert) - old_time = from_coh_ulong(old_time); + unsigned long old_time = fs32_to_cpu(sb, *sb->sv_sb_time); if (sb->sv_type == FSTYPE_SYSV4) - if (*sb->sv_sb_state == 0x7c269d38 - old_time) - *sb->sv_sb_state = 0x7c269d38 - time; - if (sb->sv_convert) - time = to_coh_ulong(time); - *sb->sv_sb_time = time; + if (*sb->sv_sb_state == cpu_to_fs32(sb, 0x7c269d38 - old_time)) + *sb->sv_sb_state = cpu_to_fs32(sb, 0x7c269d38 - time); + *sb->sv_sb_time = cpu_to_fs32(sb, time); mark_buffer_dirty(sb->sv_bh2); } sb->s_dirt = 0; @@ -550,445 +60,81 @@ static void sysv_put_super(struct super_block *sb) static int sysv_statfs(struct super_block *sb, struct statfs *buf) { - buf->f_type = sb->s_magic; /* type of filesystem */ - buf->f_bsize = sb->sv_block_size; /* block size */ - buf->f_blocks = sb->sv_ndatazones; /* total data blocks in file system */ - buf->f_bfree = sysv_count_free_blocks(sb); /* free blocks in fs */ - buf->f_bavail = buf->f_bfree; /* free blocks available to non-superuser */ - buf->f_files = sb->sv_ninodes; /* total file nodes in file system */ - buf->f_ffree = sysv_count_free_inodes(sb); /* free file nodes in fs */ + buf->f_type = sb->s_magic; + buf->f_bsize = sb->s_blocksize; + buf->f_blocks = sb->sv_ndatazones; + buf->f_bavail = buf->f_bfree = sysv_count_free_blocks(sb); + buf->f_files = sb->sv_ninodes; + buf->f_ffree = sysv_count_free_inodes(sb); buf->f_namelen = SYSV_NAMELEN; - /* Don't know what value to put in buf->f_fsid */ /* file system id */ return 0; } - -/* bmap support for running executables and shared libraries. */ - -static inline int inode_bmap(struct super_block * sb, struct inode * inode, int nr) -{ - int tmp = inode->u.sysv_i.i_data[nr]; - if (!tmp) - return 0; - return tmp + sb->sv_block_base; -} - -static int block_bmap(struct super_block * sb, struct buffer_head * bh, int nr, int convert) -{ - int tmp; - - if (!bh) - return 0; - tmp = ((sysv_zone_t *) bh->b_data) [nr]; - if (convert) - tmp = from_coh_ulong(tmp); - brelse(bh); - if (!tmp) - return 0; - return tmp + sb->sv_block_base; -} - -static unsigned int sysv_block_map(struct inode *inode, unsigned int block) -{ - struct super_block *sb; - int i, ret, convert; - - ret = 0; - lock_kernel(); - sb = inode->i_sb; - if (block < 10) { - ret = inode_bmap(sb, inode, block); - goto out; - } - block -= 10; - convert = sb->sv_convert; - if (block < sb->sv_ind_per_block) { - i = inode_bmap(sb, inode, 10); - if (!i) - goto out; - ret = block_bmap(sb, - bread(inode->i_dev, i, sb->sv_block_size), - block, convert); - goto out; - } - block -= sb->sv_ind_per_block; - if (block < sb->sv_ind_per_block_2) { - i = inode_bmap(sb, inode, 11); - if (!i) - goto out; - i = block_bmap(sb, - bread(inode->i_dev, i, sb->sv_block_size), - (block >> sb->sv_ind_per_block_bits), convert); - if (!i) - goto out; - ret = block_bmap(sb, - bread(inode->i_dev, i, sb->sv_block_size), - (block & sb->sv_ind_per_block_1), convert); - goto out; - } - block -= sb->sv_ind_per_block_2; - if (block < sb->sv_ind_per_block_3) { - i = inode_bmap(sb, inode, 12); - if (!i) - goto out; - i = block_bmap(sb, - bread(inode->i_dev, i, sb->sv_block_size), - (block >> sb->sv_ind_per_block_2_bits), convert); - if (!i) - goto out; - ret = block_bmap(sb, - bread(inode->i_dev, i, sb->sv_block_size), - ((block >> sb->sv_ind_per_block_bits) & - sb->sv_ind_per_block_1), convert); - if (!i) - goto out; - ret = block_bmap(sb, - bread(inode->i_dev, i, sb->sv_block_size), - (block & sb->sv_ind_per_block_1), convert); - goto out; - } - if ((int)block < 0) - printk("sysv_block_map: block < 0\n"); - else - printk("sysv_block_map: block > big\n"); -out: - unlock_kernel(); - return ret; -} - -/* End of bmap support. */ - - -/* Access selected blocks of regular files (or directories) */ - -static struct buffer_head *inode_getblk(struct inode *inode, int nr, int new_block, - int *err, int metadata, long *phys, int *new) -{ - struct super_block *sb; - u32 tmp; - u32 *p; - struct buffer_head * result; - - sb = inode->i_sb; - p = inode->u.sysv_i.i_data + nr; -repeat: - tmp = *p; - if (tmp) { - if (metadata) { - result = sv_getblk(sb, inode->i_dev, tmp); - if (tmp == *p) - return result; - brelse(result); - goto repeat; - } else { - *phys = tmp; - return NULL; - } - } - - tmp = sysv_new_block(sb); - if (!tmp) { - *err = -ENOSPC; - return NULL; - } - if (metadata) { - result = sv_getblk(sb, inode->i_dev, tmp); - if (*p) { - sysv_free_block(sb, tmp); - brelse(result); - goto repeat; - } +/* + * NXI <-> N0XI for PDP, XIN <-> XIN0 for le32, NIX <-> 0NIX for be32 + */ +static inline void read3byte(struct super_block *sb, + unsigned char * from, unsigned char * to) +{ + if (sb->sv_bytesex == BYTESEX_PDP) { + to[0] = from[0]; + to[1] = 0; + to[2] = from[1]; + to[3] = from[2]; + } else if (sb->sv_bytesex == BYTESEX_LE) { + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; + to[3] = 0; } else { - if (*p) { - /* - * Nobody is allowed to change block allocation - * state from under us: - */ - BUG(); - sysv_free_block(sb, tmp); - goto repeat; - } - *phys = tmp; - result = NULL; - *err = 0; - *new = 1; + to[0] = 0; + to[1] = from[0]; + to[2] = from[1]; + to[3] = from[2]; } - *p = tmp; - - inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); - return result; } -static struct buffer_head *block_getblk(struct inode *inode, - struct buffer_head *bh, int nr, int new_block, int *err, - int metadata, long *phys, int *new) +static inline void write3byte(struct super_block *sb, + unsigned char * from, unsigned char * to) { - struct super_block *sb; - u32 tmp, block; - sysv_zone_t *p; - struct buffer_head * result; - - result = NULL; - if (!bh) - goto out; - if (!buffer_uptodate(bh)) { - ll_rw_block(READ, 1, &bh); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) - goto out; - } - sb = inode->i_sb; - p = nr + (sysv_zone_t *) bh->b_data; -repeat: - block = tmp = *p; - if (sb->sv_convert) - block = from_coh_ulong(block); - if (tmp) { - if (metadata) { - result = sv_getblk(sb, bh->b_dev, block); - if (tmp == *p) - goto out; - brelse(result); - goto repeat; - } else { - *phys = tmp; - goto out; - } - } - - block = sysv_new_block(sb); - if (!block) - goto out; - if (metadata) { - result = sv_getblk(sb, bh->b_dev, block); - if (*p) { - sysv_free_block(sb, block); - brelse(result); - goto repeat; - } - memset(result->b_data, 0, sb->sv_block_size); - mark_buffer_uptodate(result, 1); - mark_buffer_dirty(result); + if (sb->sv_bytesex == BYTESEX_PDP) { + to[0] = from[0]; + to[1] = from[2]; + to[2] = from[3]; + } else if (sb->sv_bytesex == BYTESEX_LE) { + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; } else { - *phys = tmp; - *new = 1; + to[0] = from[1]; + to[1] = from[2]; + to[2] = from[3]; } - if (*p) { - sysv_free_block(sb, block); - brelse(result); - goto repeat; - } - *p = (sb->sv_convert ? to_coh_ulong(block) : block); - mark_buffer_dirty(bh); - *err = 0; -out: - brelse(bh); - return result; } -static int sysv_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create) -{ - struct super_block *sb; - int ret, err, new; - struct buffer_head *bh; - unsigned long ptr, phys; - - if (!create) { - phys = sysv_block_map(inode, iblock); - if (phys) { - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); - } - return 0; - } - - err = -EIO; - new = 0; - ret = 0; - bh = NULL; - - lock_kernel(); - sb = inode->i_sb; - if (iblock < 0) - goto abort_negative; - if (iblock > sb->sv_ind_per_block_3) - goto abort_too_big; - - err = 0; - ptr = iblock; - - /* - * ok, these macros clean the logic up a bit and make - * it much more readable: - */ -#define GET_INODE_DATABLOCK(x) \ - inode_getblk(inode, x, iblock, &err, 0, &phys, &new) -#define GET_INODE_PTR(x) \ - inode_getblk(inode, x, iblock, &err, 1, NULL, NULL) -#define GET_INDIRECT_DATABLOCK(x) \ - block_getblk (inode, bh, x, iblock, &err, 0, &phys, &new); -#define GET_INDIRECT_PTR(x) \ - block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL); - - if (ptr < 10) { - bh = GET_INODE_DATABLOCK(ptr); - goto out; - } - ptr -= 10; - if (ptr < sb->sv_ind_per_block) { - bh = GET_INODE_PTR(10); - goto get_indirect; - } - ptr -= sb->sv_ind_per_block; - if (ptr < sb->sv_ind_per_block_2) { - bh = GET_INODE_PTR(11); - goto get_double; - } - ptr -= sb->sv_ind_per_block_2; - bh = GET_INODE_PTR(12); - bh = GET_INDIRECT_PTR(ptr >> sb->sv_ind_per_block_2_bits); -get_double: - bh = GET_INDIRECT_PTR((ptr >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1); -get_indirect: - bh = GET_INDIRECT_DATABLOCK(ptr & sb->sv_ind_per_block_1); - -#undef GET_INODE_DATABLOCK -#undef GET_INODE_PTR -#undef GET_INDIRECT_DATABLOCK -#undef GET_INDIRECT_PTR - -out: - if (err) - goto abort; - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); - if (new) - bh_result->b_state |= (1UL << BH_New); -abort: - unlock_kernel(); - return err; - -abort_negative: - printk("sysv_get_block: block < 0\n"); - goto abort; - -abort_too_big: - printk("sysv_get_block: block > big\n"); - goto abort; -} - -static struct buffer_head *sysv_getblk(struct inode *inode, unsigned int block, int create) -{ - struct buffer_head dummy; - int error; - - dummy.b_state = 0; - dummy.b_blocknr = -1000; - error = sysv_get_block(inode, block, &dummy, create); - if (!error && buffer_mapped(&dummy)) { - struct buffer_head *bh; - bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->sv_block_size); - if (buffer_new(&dummy)) { - memset(bh->b_data, 0, inode->i_sb->sv_block_size); - mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh); - } - return bh; - } - return NULL; -} - -struct buffer_head *sysv_file_bread(struct inode *inode, int block, int create) -{ - struct buffer_head *bh; - - bh = sysv_getblk(inode, block, create); - if (!bh || buffer_uptodate(bh)) - return bh; - ll_rw_block(READ, 1, &bh); - wait_on_buffer(bh); - if (buffer_uptodate(bh)) - return bh; - brelse(bh); - return NULL; -} - -static int sysv_writepage(struct page *page) -{ - return block_write_full_page(page,sysv_get_block); -} -static int sysv_readpage(struct file *file, struct page *page) -{ - return block_read_full_page(page,sysv_get_block); -} -static int sysv_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) -{ - return block_prepare_write(page,from,to,sysv_get_block); -} -static int sysv_bmap(struct address_space *mapping, long block) -{ - return generic_block_bmap(mapping,block,sysv_get_block); -} -struct address_space_operations sysv_aops = { - readpage: sysv_readpage, - writepage: sysv_writepage, - sync_page: block_sync_page, - prepare_write: sysv_prepare_write, - commit_write: generic_commit_write, - bmap: sysv_bmap -}; - -#ifdef __BIG_ENDIAN - -static inline unsigned long read3byte (unsigned char * p) -{ - return (p[2] | (p[1]<<8) | (p[0]<<16)); -} - -static inline void write3byte (unsigned char *p , unsigned long val) -{ - p[2]=val&0xFF; - p[1]=(val>>8)&0xFF; - p[0]=(val>>16)&0xFF; -} - -#else - -static inline unsigned long read3byte (unsigned char * p) -{ - return (unsigned long)(*(unsigned short *)p) - | (unsigned long)(*(unsigned char *)(p+2)) << 16; -} - -static inline void write3byte (unsigned char * p, unsigned long val) -{ - *(unsigned short *)p = (unsigned short) val; - *(unsigned char *)(p+2) = val >> 16; -} - -#endif - -static inline unsigned long coh_read3byte (unsigned char * p) -{ - return (unsigned long)(*(unsigned char *)p) << 16 - | (unsigned long)(*(unsigned short *)(p+1)); -} - -static inline void coh_write3byte (unsigned char * p, unsigned long val) -{ - *(unsigned char *)p = val >> 16; - *(unsigned short *)(p+1) = (unsigned short) val; -} - -struct inode_operations sysv_symlink_inode_operations = { +static struct inode_operations sysv_symlink_inode_operations = { readlink: page_readlink, follow_link: page_follow_link, setattr: sysv_notify_change, }; +void sysv_set_inode(struct inode *inode, dev_t rdev) +{ + if (S_ISREG(inode->i_mode)) { + inode->i_op = &sysv_file_inode_operations; + inode->i_fop = &sysv_file_operations; + inode->i_mapping->a_ops = &sysv_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &sysv_dir_inode_operations; + inode->i_fop = &sysv_dir_operations; + inode->i_mapping->a_ops = &sysv_aops; + } else if (S_ISLNK(inode->i_mode)) { + inode->i_op = &sysv_symlink_inode_operations; + inode->i_mapping->a_ops = &sysv_aops; + } else + init_special_inode(inode, inode->i_mode, rdev); +} + static void sysv_read_inode(struct inode *inode) { struct super_block * sb = inode->i_sb; @@ -996,67 +142,41 @@ static void sysv_read_inode(struct inode *inode) struct sysv_inode * raw_inode; unsigned int block, ino; umode_t mode; + dev_t rdev = 0; ino = inode->i_ino; - inode->i_mode = 0; if (!ino || ino > sb->sv_ninodes) { printk("Bad inode number on dev %s" ": %d is out of range\n", kdevname(inode->i_dev), ino); return; } - block = sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits); - if (!(bh = sv_bread(sb,inode->i_dev,block))) { - printk("Major problem: unable to read inode from dev " - "%s\n", - kdevname(inode->i_dev)); + raw_inode = sysv_raw_inode(sb, ino, &bh); + if (!raw_inode) { + printk("Major problem: unable to read inode from dev %s\n", + bdevname(inode->i_dev)); return; } - raw_inode = (struct sysv_inode *) bh->b_data + ((ino-1) & sb->sv_inodes_per_block_1); - mode = raw_inode->i_mode; + mode = fs16_to_cpu(sb, raw_inode->i_mode); if (sb->sv_kludge_symlinks) mode = from_coh_imode(mode); /* SystemV FS: kludge permissions if ino==SYSV_ROOT_INO ?? */ inode->i_mode = mode; - inode->i_uid = (uid_t)raw_inode->i_uid; - inode->i_gid = (gid_t)raw_inode->i_gid; - inode->i_nlink = raw_inode->i_nlink; - if (sb->sv_convert) { - inode->i_size = from_coh_ulong(raw_inode->i_size); - inode->i_atime = from_coh_ulong(raw_inode->i_atime); - inode->i_mtime = from_coh_ulong(raw_inode->i_mtime); - inode->i_ctime = from_coh_ulong(raw_inode->i_ctime); - } else { - inode->i_size = raw_inode->i_size; - inode->i_atime = raw_inode->i_atime; - inode->i_mtime = raw_inode->i_mtime; - inode->i_ctime = raw_inode->i_ctime; - } + inode->i_uid = (uid_t)fs16_to_cpu(sb, raw_inode->i_uid); + inode->i_gid = (gid_t)fs16_to_cpu(sb, raw_inode->i_gid); + inode->i_nlink = fs16_to_cpu(sb, raw_inode->i_nlink); + inode->i_size = fs32_to_cpu(sb, raw_inode->i_size); + inode->i_atime = fs32_to_cpu(sb, raw_inode->i_atime); + inode->i_mtime = fs32_to_cpu(sb, raw_inode->i_mtime); + inode->i_ctime = fs32_to_cpu(sb, raw_inode->i_ctime); inode->i_blocks = inode->i_blksize = 0; - if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) - ; - else - if (sb->sv_convert) - for (block = 0; block < 10+1+1+1; block++) - inode->u.sysv_i.i_data[block] = - coh_read3byte(&raw_inode->i_a.i_addb[3*block]); - else - for (block = 0; block < 10+1+1+1; block++) - inode->u.sysv_i.i_data[block] = - read3byte(&raw_inode->i_a.i_addb[3*block]); - if (S_ISREG(inode->i_mode)) { - inode->i_op = &sysv_file_inode_operations; - inode->i_fop = &sysv_file_operations; - inode->i_mapping->a_ops = &sysv_aops; - } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &sysv_dir_inode_operations; - inode->i_fop = &sysv_dir_operations; - } else if (S_ISLNK(inode->i_mode)) { - inode->i_op = &sysv_symlink_inode_operations; - inode->i_mapping->a_ops = &sysv_aops; - } else - init_special_inode(inode, inode->i_mode,raw_inode->i_a.i_rdev); + for (block = 0; block < 10+1+1+1; block++) + read3byte(sb, &raw_inode->i_a.i_addb[3*block], + (unsigned char*)&inode->u.sysv_i.i_data[block]); brelse(bh); + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + rdev = (u16)fs32_to_cpu(sb, inode->u.sysv_i.i_data[0]); + sysv_set_inode(inode, rdev); } /* To avoid inconsistencies between inodes in memory and inodes on disk. */ @@ -1088,44 +208,32 @@ static struct buffer_head * sysv_update_inode(struct inode * inode) ino = inode->i_ino; if (!ino || ino > sb->sv_ninodes) { - printk("Bad inode number on dev %s" - ": %d is out of range\n", - kdevname(inode->i_dev), ino); + printk("Bad inode number on dev %s: %d is out of range\n", + bdevname(inode->i_dev), ino); return 0; } - block = sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits); - if (!(bh = sv_bread(sb,inode->i_dev,block))) { + raw_inode = sysv_raw_inode(sb, ino, &bh); + if (!raw_inode) { printk("unable to read i-node block\n"); return 0; } - raw_inode = (struct sysv_inode *) bh->b_data + ((ino-1) & sb->sv_inodes_per_block_1); mode = inode->i_mode; if (sb->sv_kludge_symlinks) mode = to_coh_imode(mode); - raw_inode->i_mode = mode; - raw_inode->i_uid = fs_high2lowuid(inode->i_uid); - raw_inode->i_gid = fs_high2lowgid(inode->i_gid); - raw_inode->i_nlink = inode->i_nlink; - if (sb->sv_convert) { - raw_inode->i_size = to_coh_ulong(inode->i_size); - raw_inode->i_atime = to_coh_ulong(inode->i_atime); - raw_inode->i_mtime = to_coh_ulong(inode->i_mtime); - raw_inode->i_ctime = to_coh_ulong(inode->i_ctime); - } else { - raw_inode->i_size = inode->i_size; - raw_inode->i_atime = inode->i_atime; - raw_inode->i_mtime = inode->i_mtime; - raw_inode->i_ctime = inode->i_ctime; - } + raw_inode->i_mode = cpu_to_fs16(sb, mode); + raw_inode->i_uid = cpu_to_fs16(sb, fs_high2lowuid(inode->i_uid)); + raw_inode->i_gid = cpu_to_fs16(sb, fs_high2lowgid(inode->i_gid)); + raw_inode->i_nlink = cpu_to_fs16(sb, inode->i_nlink); + raw_inode->i_size = cpu_to_fs32(sb, inode->i_size); + raw_inode->i_atime = cpu_to_fs32(sb, inode->i_atime); + raw_inode->i_mtime = cpu_to_fs32(sb, inode->i_mtime); + raw_inode->i_ctime = cpu_to_fs32(sb, inode->i_ctime); if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) - raw_inode->i_a.i_rdev = kdev_t_to_nr(inode->i_rdev); /* write 2 or 3 bytes ?? */ - else - if (sb->sv_convert) - for (block = 0; block < 10+1+1+1; block++) - coh_write3byte(&raw_inode->i_a.i_addb[3*block],inode->u.sysv_i.i_data[block]); - else - for (block = 0; block < 10+1+1+1; block++) - write3byte(&raw_inode->i_a.i_addb[3*block],inode->u.sysv_i.i_data[block]); + inode->u.sysv_i.i_data[0] = + cpu_to_fs32(sb, kdev_t_to_nr(inode->i_rdev)); + for (block = 0; block < 10+1+1+1; block++) + write3byte(sb, (unsigned char*)&inode->u.sysv_i.i_data[block], + &raw_inode->i_a.i_addb[3*block]); mark_buffer_dirty(bh); return bh; } @@ -1148,11 +256,9 @@ int sysv_sync_inode(struct inode * inode) if (bh && buffer_dirty(bh)) { ll_rw_block(WRITE, 1, &bh); wait_on_buffer(bh); - if (buffer_req(bh) && !buffer_uptodate(bh)) - { - printk ("IO error syncing sysv inode [" - "%s:%08lx]\n", - kdevname(inode->i_dev), inode->i_ino); + if (buffer_req(bh) && !buffer_uptodate(bh)) { + printk ("IO error syncing sysv inode [%s:%08lx]\n", + bdevname(inode->i_dev), inode->i_ino); err = -1; } } @@ -1162,21 +268,20 @@ int sysv_sync_inode(struct inode * inode) return err; } -/* Every kernel module contains stuff like this. */ - -static DECLARE_FSTYPE_DEV(sysv_fs_type, "sysv", sysv_read_super); - -static int __init init_sysv_fs(void) -{ - return register_filesystem(&sysv_fs_type); -} - -static void __exit exit_sysv_fs(void) +static void sysv_delete_inode(struct inode *inode) { - unregister_filesystem(&sysv_fs_type); + lock_kernel(); + inode->i_size = 0; + sysv_truncate(inode); + sysv_free_inode(inode); + unlock_kernel(); } -EXPORT_NO_SYMBOLS; - -module_init(init_sysv_fs) -module_exit(exit_sysv_fs) +struct super_operations sysv_sops = { + read_inode: sysv_read_inode, + write_inode: sysv_write_inode, + delete_inode: sysv_delete_inode, + put_super: sysv_put_super, + write_super: sysv_write_super, + statfs: sysv_statfs, +}; diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c new file mode 100644 index 000000000000..af27d22104ee --- /dev/null +++ b/fs/sysv/itree.c @@ -0,0 +1,440 @@ +/* + * linux/fs/sysv/itree.c + * + * Handling of indirect blocks' trees. + * AV, Sep--Dec 2000 + */ + +#include <linux/fs.h> +#include <linux/sysv_fs.h> +#include <linux/locks.h> +#include <linux/smp_lock.h> + +enum {DIRECT = 10, DEPTH = 4}; /* Have triple indirect */ + +static inline void dirty_indirect(struct buffer_head *bh, struct inode *inode) +{ + mark_buffer_dirty_inode(bh, inode); + if (IS_SYNC(inode)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } +} + +static int block_to_path(struct inode *inode, long block, int offsets[DEPTH]) +{ + struct super_block *sb = inode->i_sb; + int ptrs_bits = sb->sv_ind_per_block_bits; + unsigned long indirect_blocks = sb->sv_ind_per_block, + double_blocks = sb->sv_ind_per_block_2; + int n = 0; + + if (block < 0) { + printk("sysv_block_map: block < 0\n"); + } else if (block < DIRECT) { + offsets[n++] = block; + } else if ( (block -= DIRECT) < indirect_blocks) { + offsets[n++] = DIRECT; + offsets[n++] = block; + } else if ((block -= indirect_blocks) < double_blocks) { + offsets[n++] = DIRECT+1; + offsets[n++] = block >> ptrs_bits; + offsets[n++] = block & (indirect_blocks - 1); + } else if (((block -= double_blocks) >> (ptrs_bits * 2)) < indirect_blocks) { + offsets[n++] = DIRECT+2; + offsets[n++] = block >> (ptrs_bits * 2); + offsets[n++] = (block >> ptrs_bits) & (indirect_blocks - 1); + offsets[n++] = block & (indirect_blocks - 1); + } else { + /* nothing */; + } + return n; +} + +static inline int block_to_cpu(struct super_block *sb, u32 nr) +{ + return sb->sv_block_base + fs32_to_cpu(sb, nr); +} + +typedef struct { + u32 *p; + u32 key; + struct buffer_head *bh; +} Indirect; + +static inline void add_chain(Indirect *p, struct buffer_head *bh, u32 *v) +{ + p->key = *(p->p = v); + p->bh = bh; +} + +static inline int verify_chain(Indirect *from, Indirect *to) +{ + while (from <= to && from->key == *from->p) + from++; + return (from > to); +} + +static inline u32 *block_end(struct buffer_head *bh) +{ + return (u32*)((char*)bh->b_data + bh->b_size); +} + +static Indirect *get_branch(struct inode *inode, + int depth, + int offsets[], + Indirect chain[], + int *err) +{ + kdev_t dev = inode->i_dev; + int size = inode->i_sb->s_blocksize; + Indirect *p = chain; + struct buffer_head *bh; + + *err = 0; + add_chain (chain, NULL, inode->u.sysv_i.i_data + *offsets); + if (!p->key) + goto no_block; + while (--depth) { + int block = block_to_cpu(inode->i_sb, p->key); + bh = bread(dev, block, size); + if (!bh) + goto failure; + if (!verify_chain(chain, p)) + goto changed; + add_chain(++p, bh, (u32*)bh->b_data + *++offsets); + if (!p->key) + goto no_block; + } + return NULL; + +changed: + *err = -EAGAIN; + goto no_block; +failure: + *err = -EIO; +no_block: + return p; +} + +static int alloc_branch(struct inode *inode, + int num, + int *offsets, + Indirect *branch) +{ + int blocksize = inode->i_sb->s_blocksize; + int n = 0; + int i; + + branch[0].key = sysv_new_block(inode->i_sb); + if (branch[0].key) for (n = 1; n < num; n++) { + struct buffer_head *bh; + int parent; + /* Allocate the next block */ + branch[n].key = sysv_new_block(inode->i_sb); + if (!branch[n].key) + break; + /* + * Get buffer_head for parent block, zero it out and set + * the pointer to new one, then send parent to disk. + */ + parent = block_to_cpu(inode->i_sb, branch[n-1].key); + bh = getblk(inode->i_dev, parent, blocksize); + lock_buffer(bh); + memset(bh->b_data, 0, blocksize); + branch[n].bh = bh; + branch[n].p = (u32*) bh->b_data + offsets[n]; + *branch[n].p = branch[n].key; + mark_buffer_uptodate(bh, 1); + unlock_buffer(bh); + dirty_indirect(bh, inode); + } + if (n == num) + return 0; + + /* Allocation failed, free what we already allocated */ + for (i = 1; i < n; i++) + bforget(branch[i].bh); + for (i = 0; i < n; i++) + sysv_free_block(inode->i_sb, branch[i].key); + return -ENOSPC; +} + +static inline int splice_branch(struct inode *inode, + Indirect chain[], + Indirect *where, + int num) +{ + int i; + /* Verify that place we are splicing to is still there and vacant */ + + if (!verify_chain(chain, where-1) || *where->p) + goto changed; + + *where->p = where->key; + inode->i_ctime = CURRENT_TIME; + + /* had we spliced it onto indirect block? */ + if (where->bh) + dirty_indirect(where->bh, inode); + + if (IS_SYNC(inode)) + sysv_sync_inode(inode); + else + mark_inode_dirty(inode); + return 0; + +changed: + for (i = 1; i < num; i++) + bforget(where[i].bh); + for (i = 0; i < num; i++) + sysv_free_block(inode->i_sb, where[i].key); + return -EAGAIN; +} + +static int get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create) +{ + int err = -EIO; + int offsets[DEPTH]; + Indirect chain[DEPTH]; + struct super_block *sb = inode->i_sb; + Indirect *partial; + int left; + int depth = block_to_path(inode, iblock, offsets); + + if (depth == 0) + goto out; + + lock_kernel(); +reread: + partial = get_branch(inode, depth, offsets, chain, &err); + + /* Simplest case - block found, no allocation needed */ + if (!partial) { +got_it: + bh_result->b_dev = sb->s_dev; + bh_result->b_blocknr = block_to_cpu(sb, chain[depth-1].key); + bh_result->b_state |= (1UL << BH_Mapped); + /* Clean up and exit */ + partial = chain+depth-1; /* the whole chain */ + goto cleanup; + } + + /* Next simple case - plain lookup or failed read of indirect block */ + if (!create || err == -EIO) { +cleanup: + while (partial > chain) { + brelse(partial->bh); + partial--; + } + unlock_kernel(); +out: + return err; + } + + /* + * Indirect block might be removed by truncate while we were + * reading it. Handling of that case (forget what we've got and + * reread) is taken out of the main path. + */ + if (err == -EAGAIN) + goto changed; + + left = (chain + depth) - partial; + err = alloc_branch(inode, left, offsets+(partial-chain), partial); + if (err) + goto cleanup; + + if (splice_branch(inode, chain, partial, left) < 0) + goto changed; + + bh_result->b_state |= (1UL << BH_New); + goto got_it; + +changed: + while (partial > chain) { + brelse(partial->bh); + partial--; + } + goto reread; +} + +static inline int all_zeroes(u32 *p, u32 *q) +{ + while (p < q) + if (*p++) + return 0; + return 1; +} + +static Indirect *find_shared(struct inode *inode, + int depth, + int offsets[], + Indirect chain[], + u32 *top) +{ + Indirect *partial, *p; + int k, err; + + *top = 0; + for (k = depth; k > 1 && !offsets[k-1]; k--) + ; + partial = get_branch(inode, k, offsets, chain, &err); + if (!partial) + partial = chain + k-1; + /* + * If the branch acquired continuation since we've looked at it - + * fine, it should all survive and (new) top doesn't belong to us. + */ + if (!partial->key && *partial->p) + goto no_top; + for (p=partial; p>chain && all_zeroes((u32*)p->bh->b_data,p->p); p--) + ; + /* + * OK, we've found the last block that must survive. The rest of our + * branch should be detached before unlocking. However, if that rest + * of branch is all ours and does not grow immediately from the inode + * it's easier to cheat and just decrement partial->p. + */ + if (p == chain + k - 1 && p > chain) { + p->p--; + } else { + *top = *p->p; + *p->p = 0; + } + + while(partial > p) { + brelse(partial->bh); + partial--; + } +no_top: + return partial; +} + +static inline void free_data(struct inode *inode, u32 *p, u32 *q) +{ + for ( ; p < q ; p++) { + u32 nr = *p; + if (nr) { + *p = 0; + sysv_free_block(inode->i_sb, nr); + mark_inode_dirty(inode); + } + } +} + +static void free_branches(struct inode *inode, u32 *p, u32 *q, int depth) +{ + struct buffer_head * bh; + struct super_block *sb = inode->i_sb; + + if (depth--) { + for ( ; p < q ; p++) { + int block; + u32 nr = *p; + if (!nr) + continue; + *p = 0; + block = block_to_cpu(sb, nr); + bh = bread(inode->i_dev, block, sb->s_blocksize); + if (!bh) + continue; + free_branches(inode, (u32*)bh->b_data, + block_end(bh), depth); + bforget(bh); + sysv_free_block(sb, nr); + mark_inode_dirty(inode); + } + } else + free_data(inode, p, q); +} + +void sysv_truncate (struct inode * inode) +{ + u32 *i_data = inode->u.sysv_i.i_data; + int offsets[DEPTH]; + Indirect chain[DEPTH]; + Indirect *partial; + int nr = 0; + int n; + long iblock; + unsigned blocksize; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + + blocksize = inode->i_sb->s_blocksize; + iblock = (inode->i_size + blocksize-1) + >> inode->i_sb->s_blocksize_bits; + + block_truncate_page(inode->i_mapping, inode->i_size, get_block); + + n = block_to_path(inode, iblock, offsets); + if (n == 0) + return; + + if (n == 1) { + free_data(inode, i_data+offsets[0], i_data + DIRECT); + goto do_indirects; + } + + partial = find_shared(inode, n, offsets, chain, &nr); + /* Kill the top of shared branch (already detached) */ + if (nr) { + if (partial == chain) + mark_inode_dirty(inode); + else + dirty_indirect(partial->bh, inode); + free_branches(inode, &nr, &nr+1, (chain+n-1) - partial); + } + /* Clear the ends of indirect blocks on the shared branch */ + while (partial > chain) { + free_branches(inode, partial->p + 1, block_end(partial->bh), + (chain+n-1) - partial); + dirty_indirect(partial->bh, inode); + brelse (partial->bh); + partial--; + } +do_indirects: + /* Kill the remaining (whole) subtrees (== subtrees deeper than...) */ + while (n < DEPTH) { + nr = i_data[DIRECT + n - 1]; + if (nr) { + i_data[DIRECT + n - 1] = 0; + mark_inode_dirty(inode); + free_branches(inode, &nr, &nr+1, n); + } + n++; + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + if (IS_SYNC(inode)) + sysv_sync_inode (inode); + else + mark_inode_dirty(inode); +} + +static int sysv_writepage(struct page *page) +{ + return block_write_full_page(page,get_block); +} +static int sysv_readpage(struct file *file, struct page *page) +{ + return block_read_full_page(page,get_block); +} +static int sysv_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) +{ + return block_prepare_write(page,from,to,get_block); +} +static int sysv_bmap(struct address_space *mapping, long block) +{ + return generic_block_bmap(mapping,block,get_block); +} +struct address_space_operations sysv_aops = { + readpage: sysv_readpage, + writepage: sysv_writepage, + sync_page: block_sync_page, + prepare_write: sysv_prepare_write, + commit_write: generic_commit_write, + bmap: sysv_bmap +}; diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index aba233768703..537126396a04 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -12,108 +12,70 @@ * Copyright (C) 1997, 1998 Krzysztof G. Baranowski */ - -#include <linux/sched.h> -#include <linux/kernel.h> #include <linux/fs.h> #include <linux/sysv_fs.h> -#include <linux/string.h> -#include <linux/stat.h> -#include <linux/errno.h> +#include <linux/pagemap.h> -/* compare strings: name[0..len-1] (not zero-terminated) and - * buffer[0..] (filled with zeroes up to buffer[0..maxlen-1]) - */ -static inline int namecompare(int len, int maxlen, - const char * name, const char * buffer) +static inline void inc_count(struct inode *inode) { - if (len > maxlen) - return 0; - if (len < maxlen && buffer[len]) - return 0; - return !memcmp(name, buffer, len); + inode->i_nlink++; + mark_inode_dirty(inode); } -/* - * ok, we cannot use strncmp, as the name is not in our data space. [Now it is!] - * Thus we'll have to use sysv_match. No big problem. Match also makes - * some sanity tests. - * - * NOTE! unlike strncmp, sysv_match returns 1 for success, 0 for failure. - */ -static int sysv_match(int len, const char * name, struct sysv_dir_entry * de) +static inline void dec_count(struct inode *inode) { - if (!de->inode || len > SYSV_NAMELEN) - return 0; - /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ - if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) - return 1; - return namecompare(len, SYSV_NAMELEN, name, de->name); + inode->i_nlink--; + mark_inode_dirty(inode); } -/* - * sysv_find_entry() - * - * finds an entry in the specified directory with the wanted name. It - * returns the cache buffer in which the entry was found, and the entry - * itself (as a parameter - res_dir). It does NOT read the inode of the - * entry - you'll have to do that yourself if you want to. - */ -static struct buffer_head * sysv_find_entry(struct inode * dir, - const char * name, int namelen, struct sysv_dir_entry ** res_dir) +static int add_nondir(struct dentry *dentry, struct inode *inode) { - struct super_block * sb; - unsigned long pos, block, offset; /* pos = block * block_size + offset */ - struct buffer_head * bh; - - *res_dir = NULL; - sb = dir->i_sb; - if (namelen > SYSV_NAMELEN) { - if (sb->sv_truncate) - namelen = SYSV_NAMELEN; - else - return NULL; - } - bh = NULL; - pos = block = offset = 0; - while (pos < dir->i_size) { - if (!bh) { - bh = sysv_file_bread(dir, block, 0); - if (!bh) { - /* offset = 0; */ block++; - pos += sb->sv_block_size; - continue; - } - } - if (sysv_match(namelen, name, - *res_dir = (struct sysv_dir_entry *) (bh->b_data + offset) )) - return bh; - pos += SYSV_DIRSIZE; - offset += SYSV_DIRSIZE; - if (offset < sb->sv_block_size) - continue; - brelse(bh); - bh = NULL; - offset = 0; block++; + int err = sysv_add_link(dentry, inode); + if (!err) { + d_instantiate(dentry, inode); + return 0; } - brelse(bh); - *res_dir = NULL; - return NULL; + dec_count(inode); + iput(inode); + return err; } +static int sysv_hash(struct dentry *dentry, struct qstr *qstr) +{ + unsigned long hash; + int i; + const unsigned char *name; + + i = SYSV_NAMELEN; + if (i >= qstr->len) + return 0; + /* Truncate the name in place, avoids having to define a compare + function. */ + qstr->len = i; + name = qstr->name; + hash = init_name_hash(); + while (i--) + hash = partial_name_hash(*name++, hash); + qstr->hash = end_name_hash(hash); + return 0; +} + +struct dentry_operations sysv_dentry_operations = { + d_hash: sysv_hash, +}; + static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry) { struct inode * inode = NULL; - struct sysv_dir_entry * de; - struct buffer_head * bh; + ino_t ino; - bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); + dentry->d_op = dir->i_sb->s_root->d_op; + if (dentry->d_name.len > SYSV_NAMELEN) + return ERR_PTR(-ENAMETOOLONG); + ino = sysv_inode_by_name(dentry); - if (bh) { - int ino = de->inode; - brelse(bh); + if (ino) { inode = iget(dir->i_sb, ino); - if (!inode) return ERR_PTR(-EACCES); } @@ -121,399 +83,146 @@ static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry) return NULL; } -/* - * sysv_add_entry() - * - * adds a file entry to the specified directory, returning a possible - * error value if it fails. - * - * NOTE!! The inode part of 'de' is left at 0 - which means you - * may not sleep between calling this and putting something into - * the entry, as someone else might have used it while you slept. - */ -static int sysv_add_entry(struct inode * dir, - const char * name, int namelen, - struct buffer_head ** res_buf, - struct sysv_dir_entry ** res_dir) -{ - struct super_block * sb; - int i; - unsigned long pos, block, offset; /* pos = block * block_size + offset */ - struct buffer_head * bh; - struct sysv_dir_entry * de; - - *res_buf = NULL; - *res_dir = NULL; - sb = dir->i_sb; - if (namelen > SYSV_NAMELEN) { - if (sb->sv_truncate) - namelen = SYSV_NAMELEN; - else - return -ENAMETOOLONG; - } - if (!namelen) - return -ENOENT; - bh = NULL; - pos = block = offset = 0; - while (1) { - if (!bh) { - bh = sysv_file_bread(dir, block, 1); - if (!bh) - return -ENOSPC; - } - de = (struct sysv_dir_entry *) (bh->b_data + offset); - pos += SYSV_DIRSIZE; - offset += SYSV_DIRSIZE; - if (pos > dir->i_size) { - de->inode = 0; - dir->i_size = pos; - mark_inode_dirty(dir); - } - if (de->inode) { - if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) { - brelse(bh); - return -EEXIST; - } - } else { - dir->i_mtime = dir->i_ctime = CURRENT_TIME; - mark_inode_dirty(dir); - for (i = 0; i < SYSV_NAMELEN ; i++) - de->name[i] = (i < namelen) ? name[i] : 0; - mark_buffer_dirty(bh); - *res_dir = de; - break; - } - if (offset < sb->sv_block_size) - continue; - brelse(bh); - bh = NULL; - offset = 0; block++; - } - *res_buf = bh; - return 0; -} - -static int sysv_create(struct inode * dir, struct dentry * dentry, int mode) +static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev) { - int error; - struct inode * inode; - struct buffer_head * bh; - struct sysv_dir_entry * de; - - inode = sysv_new_inode(dir); - if (!inode) + struct inode * inode = sysv_new_inode(dir, mode); + if (!inode) return -ENOSPC; - inode->i_op = &sysv_file_inode_operations; - inode->i_fop = &sysv_file_operations; - inode->i_mapping->a_ops = &sysv_aops; - inode->i_mode = mode; + sysv_set_inode(inode, rdev); mark_inode_dirty(inode); - error = sysv_add_entry(dir, dentry->d_name.name, - dentry->d_name.len, &bh, &de); - if (error) { - inode->i_nlink--; - mark_inode_dirty(inode); - iput(inode); - return error; - } - de->inode = inode->i_ino; - mark_buffer_dirty(bh); - brelse(bh); - d_instantiate(dentry, inode); - return 0; + return add_nondir(dentry, inode); } -static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev) +static int sysv_create(struct inode * dir, struct dentry * dentry, int mode) { - int error; - struct inode * inode; - struct buffer_head * bh; - struct sysv_dir_entry * de; - - bh = sysv_find_entry(dir, dentry->d_name.name, - dentry->d_name.len, &de); - if (bh) { - brelse(bh); - return -EEXIST; - } - inode = sysv_new_inode(dir); - if (!inode) - return -ENOSPC; - inode->i_uid = current->fsuid; - init_special_inode(inode, mode, rdev); - mark_inode_dirty(inode); - error = sysv_add_entry(dir, dentry->d_name.name, - dentry->d_name.len, &bh, &de); - if (error) { - inode->i_nlink--; - mark_inode_dirty(inode); - iput(inode); - return error; - } - de->inode = inode->i_ino; - mark_buffer_dirty(bh); - brelse(bh); - d_instantiate(dentry, inode); - return 0; + return sysv_mknod(dir, dentry, mode, 0); } -static int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode) +static int sysv_symlink(struct inode * dir, struct dentry * dentry, + const char * symname) { - int error; + int err = -ENAMETOOLONG; + int l = strlen(symname)+1; struct inode * inode; - struct buffer_head * bh, *dir_block; - struct sysv_dir_entry * de; - bh = sysv_find_entry(dir, dentry->d_name.name, - dentry->d_name.len, &de); - if (bh) { - brelse(bh); - return -EEXIST; - } - if (dir->i_nlink >= dir->i_sb->sv_link_max) - return -EMLINK; - inode = sysv_new_inode(dir); + if (l > dir->i_sb->s_blocksize) + goto out; + + err = -ENOSPC; + inode = sysv_new_inode(dir, S_IFLNK|0777); if (!inode) - return -ENOSPC; - inode->i_op = &sysv_dir_inode_operations; - inode->i_fop = &sysv_dir_operations; - inode->i_size = 2 * SYSV_DIRSIZE; - dir_block = sysv_file_bread(inode,0,1); - if (!dir_block) { - inode->i_nlink--; - mark_inode_dirty(inode); - iput(inode); - return -ENOSPC; - } - de = (struct sysv_dir_entry *) (dir_block->b_data + 0*SYSV_DIRSIZE); - de->inode = inode->i_ino; - strcpy(de->name,"."); /* rest of de->name is zero, see sysv_new_block */ - de = (struct sysv_dir_entry *) (dir_block->b_data + 1*SYSV_DIRSIZE); - de->inode = dir->i_ino; - strcpy(de->name,".."); /* rest of de->name is zero, see sysv_new_block */ - inode->i_nlink = 2; - mark_buffer_dirty(dir_block); - brelse(dir_block); - inode->i_mode = S_IFDIR | mode; - if (dir->i_mode & S_ISGID) - inode->i_mode |= S_ISGID; - mark_inode_dirty(inode); - error = sysv_add_entry(dir, dentry->d_name.name, - dentry->d_name.len, &bh, &de); - if (error) { - inode->i_nlink=0; - iput(inode); - return error; - } - de->inode = inode->i_ino; - mark_buffer_dirty(bh); - dir->i_nlink++; - mark_inode_dirty(dir); - brelse(bh); - d_instantiate(dentry, inode); - return 0; -} + goto out; -/* - * routine to check that the specified directory is empty (for rmdir) - */ -static int empty_dir(struct inode * inode) -{ - struct super_block * sb; - unsigned long pos, block, offset; /* pos = block * block_size + offset */ - struct buffer_head * bh; - struct sysv_dir_entry * de; + sysv_set_inode(inode, 0); + err = block_symlink(inode, symname, l); + if (err) + goto out_fail; - block = 0; - bh = NULL; - pos = offset = 2*SYSV_DIRSIZE; - if ((unsigned long)(inode->i_size) % SYSV_DIRSIZE) - goto bad_dir; - if (inode->i_size < pos) - goto bad_dir; - bh = sysv_file_bread(inode, 0, 0); - if (!bh) - goto bad_dir; - de = (struct sysv_dir_entry *) (bh->b_data + 0*SYSV_DIRSIZE); - if (!de->inode || strcmp(de->name,".")) - goto bad_dir; - de = (struct sysv_dir_entry *) (bh->b_data + 1*SYSV_DIRSIZE); - if (!de->inode || strcmp(de->name,"..")) - goto bad_dir; - sb = inode->i_sb; - while (pos < inode->i_size) { - if (!bh) { - bh = sysv_file_bread(inode, block, 0); - if (!bh) { - /* offset = 0; */ block++; - pos += sb->sv_block_size; - continue; - } - } - de = (struct sysv_dir_entry *) (bh->b_data + offset); - pos += SYSV_DIRSIZE; - offset += SYSV_DIRSIZE; - if (de->inode) { - brelse(bh); - return 0; - } - if (offset < sb->sv_block_size) - continue; - brelse(bh); - bh = NULL; - offset = 0; block++; - } - brelse(bh); - return 1; -bad_dir: - brelse(bh); - printk("Bad directory on device %s\n", - kdevname(inode->i_dev)); - return 1; + err = add_nondir(dentry, inode); +out: + return err; + +out_fail: + dec_count(inode); + iput(inode); + goto out; } -static int sysv_rmdir(struct inode * dir, struct dentry * dentry) +static int sysv_link(struct dentry * old_dentry, struct inode * dir, + struct dentry * dentry) { - int retval; - struct inode * inode; - struct buffer_head * bh; - struct sysv_dir_entry * de; + struct inode *inode = old_dentry->d_inode; - inode = dentry->d_inode; - bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); - retval = -ENOENT; - if (!bh || de->inode != inode->i_ino) - goto end_rmdir; + if (S_ISDIR(inode->i_mode)) + return -EPERM; - if (!empty_dir(inode)) { - retval = -ENOTEMPTY; - goto end_rmdir; - } - if (inode->i_nlink != 2) - printk("empty directory has nlink!=2 (%d)\n", inode->i_nlink); - de->inode = 0; - mark_buffer_dirty(bh); - inode->i_nlink=0; - dir->i_nlink--; - inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; - mark_inode_dirty(inode); - mark_inode_dirty(dir); - retval = 0; -end_rmdir: - brelse(bh); - return retval; -} + if (inode->i_nlink >= inode->i_sb->sv_link_max) + return -EMLINK; -static int sysv_unlink(struct inode * dir, struct dentry * dentry) -{ - int retval; - struct inode * inode; - struct buffer_head * bh; - struct sysv_dir_entry * de; + inode->i_ctime = CURRENT_TIME; + inc_count(inode); + atomic_inc(&inode->i_count); - retval = -ENOENT; - inode = dentry->d_inode; - bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); - if (!bh || de->inode != inode->i_ino) - goto end_unlink; - if (!inode->i_nlink) { - printk("Deleting nonexistent file (%s:%lu), %d\n", - kdevname(inode->i_dev), inode->i_ino, inode->i_nlink); - inode->i_nlink=1; - } - de->inode = 0; - mark_buffer_dirty(bh); - dir->i_ctime = dir->i_mtime = CURRENT_TIME; - mark_inode_dirty(dir); - inode->i_nlink--; - inode->i_ctime = dir->i_ctime; - mark_inode_dirty(inode); - retval = 0; -end_unlink: - brelse(bh); - return retval; + return add_nondir(dentry, inode); } -static int sysv_symlink(struct inode * dir, struct dentry * dentry, - const char * symname) +static int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode) { struct inode * inode; - struct sysv_dir_entry * de; - struct buffer_head * bh; - int err; - int l; + int err = -EMLINK; - err = -ENAMETOOLONG; - l = strlen(symname)+1; - if (l > dir->i_sb->sv_block_size_1) + if (dir->i_nlink >= dir->i_sb->sv_link_max) goto out; + + inc_count(dir); + + if (dir->i_mode & S_ISGID) + mode |= S_ISGID; + err = -ENOSPC; - if (!(inode = sysv_new_inode(dir))) - goto out; + inode = sysv_new_inode(dir, S_IFDIR|mode); + if (!inode) + goto out_dir; + sysv_set_inode(inode, 0); - inode->i_mode = S_IFLNK | 0777; - inode->i_op = &sysv_symlink_inode_operations; - inode->i_mapping->a_ops = &sysv_aops; - err = block_symlink(inode, symname, l); + inc_count(inode); + + err = sysv_make_empty(inode, dir); if (err) - goto out_no_entry; - mark_inode_dirty(inode); - err = sysv_add_entry(dir, dentry->d_name.name, - dentry->d_name.len, &bh, &de); + goto out_fail; + + err = sysv_add_link(dentry, inode); if (err) - goto out_no_entry; - de->inode = inode->i_ino; - mark_buffer_dirty(bh); - brelse(bh); + goto out_fail; + d_instantiate(dentry, inode); out: return err; -out_no_entry: - inode->i_nlink--; - mark_inode_dirty(inode); + +out_fail: + dec_count(inode); + dec_count(inode); iput(inode); +out_dir: + dec_count(dir); goto out; } -static int sysv_link(struct dentry * old_dentry, struct inode * dir, - struct dentry * dentry) +static int sysv_unlink(struct inode * dir, struct dentry * dentry) { - struct inode *oldinode = old_dentry->d_inode; - int error; + struct inode * inode = dentry->d_inode; + struct page * page; struct sysv_dir_entry * de; - struct buffer_head * bh; + int err = -ENOENT; - if (S_ISDIR(oldinode->i_mode)) { - return -EPERM; - } - if (oldinode->i_nlink >= oldinode->i_sb->sv_link_max) { - return -EMLINK; - } - bh = sysv_find_entry(dir, dentry->d_name.name, - dentry->d_name.len, &de); - if (bh) { - brelse(bh); - return -EEXIST; - } - error = sysv_add_entry(dir, dentry->d_name.name, - dentry->d_name.len, &bh, &de); - if (error) { - brelse(bh); - return error; - } - de->inode = oldinode->i_ino; - mark_buffer_dirty(bh); - brelse(bh); - oldinode->i_nlink++; - oldinode->i_ctime = CURRENT_TIME; - mark_inode_dirty(oldinode); - atomic_inc(&oldinode->i_count); - d_instantiate(dentry, oldinode); - return 0; + de = sysv_find_entry(dentry, &page); + if (!de) + goto out; + + err = sysv_delete_entry (de, page); + if (err) + goto out; + + inode->i_ctime = dir->i_ctime; + dec_count(inode); +out: + return err; } -#define PARENT_INO(buffer) \ -(((struct sysv_dir_entry *) ((buffer) + 1*SYSV_DIRSIZE))->inode) +static int sysv_rmdir(struct inode * dir, struct dentry * dentry) +{ + struct inode *inode = dentry->d_inode; + int err = -ENOTEMPTY; + + if (sysv_empty_dir(inode)) { + err = sysv_unlink(dir, dentry); + if (!err) { + dec_count(inode); + dec_count(dir); + } + } + return err; +} /* * Anybody can rename anything with this: the permission checks are left to the @@ -522,83 +231,78 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir, static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry, struct inode * new_dir, struct dentry * new_dentry) { - struct inode * old_inode, * new_inode; - struct buffer_head * old_bh, * new_bh, * dir_bh; - struct sysv_dir_entry * old_de, * new_de; - int retval; - - old_inode = old_dentry->d_inode; - new_inode = new_dentry->d_inode; - new_bh = dir_bh = NULL; - old_bh = sysv_find_entry(old_dir, old_dentry->d_name.name, - old_dentry->d_name.len, &old_de); - retval = -ENOENT; - if (!old_bh || old_de->inode != old_inode->i_ino) - goto end_rename; - retval = -EPERM; - new_bh = sysv_find_entry(new_dir, new_dentry->d_name.name, - new_dentry->d_name.len, &new_de); - if (new_bh) { - if (!new_inode) { - brelse(new_bh); - new_bh = NULL; - } - } + struct inode * old_inode = old_dentry->d_inode; + struct inode * new_inode = new_dentry->d_inode; + struct page * dir_page = NULL; + struct sysv_dir_entry * dir_de = NULL; + struct page * old_page; + struct sysv_dir_entry * old_de; + int err = -ENOENT; + + old_de = sysv_find_entry(old_dentry, &old_page); + if (!old_de) + goto out; + if (S_ISDIR(old_inode->i_mode)) { - if (new_inode) { - retval = -ENOTEMPTY; - if (!empty_dir(new_inode)) - goto end_rename; - } - retval = -EIO; - dir_bh = sysv_file_bread(old_inode, 0, 0); - if (!dir_bh) - goto end_rename; - if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) - goto end_rename; - retval = -EMLINK; - if (!new_inode && new_dir != old_dir && - new_dir->i_nlink >= new_dir->i_sb->sv_link_max) - goto end_rename; + err = -EIO; + dir_de = sysv_dotdot(old_inode, &dir_page); + if (!dir_de) + goto out_old; } - if (!new_bh) { - retval = sysv_add_entry(new_dir, new_dentry->d_name.name, - new_dentry->d_name.len, &new_bh, &new_de); - if (retval) - goto end_rename; - } - new_de->inode = old_inode->i_ino; - old_de->inode = 0; - old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; - mark_inode_dirty(old_dir); - new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME; - mark_inode_dirty(new_dir); + if (new_inode) { - new_inode->i_nlink--; + struct page * new_page; + struct sysv_dir_entry * new_de; + + err = -ENOTEMPTY; + if (dir_de && !sysv_empty_dir(new_inode)) + goto out_dir; + + err = -ENOENT; + new_de = sysv_find_entry(new_dentry, &new_page); + if (!new_de) + goto out_dir; + inc_count(old_inode); + sysv_set_link(new_de, new_page, old_inode); new_inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(new_inode); - } - mark_buffer_dirty(old_bh); - mark_buffer_dirty(new_bh); - if (dir_bh) { - PARENT_INO(dir_bh->b_data) = new_dir->i_ino; - mark_buffer_dirty(dir_bh); - old_dir->i_nlink--; - mark_inode_dirty(old_dir); - if (new_inode) { + if (dir_de) new_inode->i_nlink--; - mark_inode_dirty(new_inode); - } else { - new_dir->i_nlink++; - mark_inode_dirty(new_dir); + dec_count(new_inode); + } else { + if (dir_de) { + err = -EMLINK; + if (new_dir->i_nlink >= new_dir->i_sb->sv_link_max) + goto out_dir; + } + inc_count(old_inode); + err = sysv_add_link(new_dentry, old_inode); + if (err) { + dec_count(old_inode); + goto out_dir; } + if (dir_de) + inc_count(new_dir); + } + + sysv_delete_entry(old_de, old_page); + dec_count(old_inode); + + if (dir_de) { + sysv_set_link(dir_de, dir_page, new_dir); + dec_count(old_dir); } - retval = 0; -end_rename: - brelse(dir_bh); - brelse(old_bh); - brelse(new_bh); - return retval; + return 0; + +out_dir: + if (dir_de) { + kunmap(dir_page); + page_cache_release(dir_page); + } +out_old: + kunmap(old_page); + page_cache_release(old_page); +out: + return err; } /* diff --git a/fs/sysv/super.c b/fs/sysv/super.c new file mode 100644 index 000000000000..4c3b14e523c1 --- /dev/null +++ b/fs/sysv/super.c @@ -0,0 +1,467 @@ +/* + * linux/fs/sysv/inode.c + * + * minix/inode.c + * Copyright (C) 1991, 1992 Linus Torvalds + * + * xenix/inode.c + * Copyright (C) 1992 Doug Evans + * + * coh/inode.c + * Copyright (C) 1993 Pascal Haible, Bruno Haible + * + * sysv/inode.c + * Copyright (C) 1993 Paul B. Monday + * + * sysv/inode.c + * Copyright (C) 1993 Bruno Haible + * Copyright (C) 1997, 1998 Krzysztof G. Baranowski + * + * This file contains code for read/parsing the superblock. + */ + +#include <linux/module.h> + +#include <linux/fs.h> +#include <linux/sysv_fs.h> +#include <linux/init.h> + +/* The following functions try to recognize specific filesystems. + * We recognize: + * - Xenix FS by its magic number. + * - SystemV FS by its magic number. + * - Coherent FS by its funny fname/fpack field. + * We discriminate among SystemV4 and SystemV2 FS by the assumption that + * the time stamp is not < 01-01-1980. + */ + +enum { + JAN_1_1980 = (10*365 + 2) * 24 * 60 * 60 +}; + +static void detected_xenix(struct super_block *sb) +{ + struct buffer_head *bh1 = sb->sv_bh1; + struct buffer_head *bh2 = sb->sv_bh2; + struct xenix_super_block * sbd1; + struct xenix_super_block * sbd2; + + if (bh1 != bh2) + sbd1 = sbd2 = (struct xenix_super_block *) bh1->b_data; + else { + /* block size = 512, so bh1 != bh2 */ + sbd1 = (struct xenix_super_block *) bh1->b_data; + sbd2 = (struct xenix_super_block *) (bh2->b_data - 512); + } + + sb->sv_link_max = XENIX_LINK_MAX; + sb->sv_fic_size = XENIX_NICINOD; + sb->sv_flc_size = XENIX_NICFREE; + sb->sv_sbd1 = (char *) sbd1; + sb->sv_sbd2 = (char *) sbd2; + sb->sv_sb_fic_count = &sbd1->s_ninode; + sb->sv_sb_fic_inodes = &sbd1->s_inode[0]; + sb->sv_sb_total_free_inodes = &sbd2->s_tinode; + sb->sv_bcache_count = &sbd1->s_nfree; + sb->sv_bcache = &sbd1->s_free[0]; + sb->sv_free_blocks = &sbd2->s_tfree; + sb->sv_sb_time = &sbd2->s_time; + sb->sv_firstdatazone = fs16_to_cpu(sb, sbd1->s_isize); + sb->sv_nzones = fs32_to_cpu(sb, sbd1->s_fsize); +} + +static void detected_sysv4(struct super_block *sb) +{ + struct sysv4_super_block * sbd; + struct buffer_head *bh1 = sb->sv_bh1; + struct buffer_head *bh2 = sb->sv_bh2; + + if (bh1 == bh2) + sbd = (struct sysv4_super_block *) (bh1->b_data + BLOCK_SIZE/2); + else + sbd = (struct sysv4_super_block *) bh2->b_data; + + sb->sv_link_max = SYSV_LINK_MAX; + sb->sv_fic_size = SYSV_NICINOD; + sb->sv_flc_size = SYSV_NICFREE; + sb->sv_sbd1 = (char *) sbd; + sb->sv_sbd2 = (char *) sbd; + sb->sv_sb_fic_count = &sbd->s_ninode; + sb->sv_sb_fic_inodes = &sbd->s_inode[0]; + sb->sv_sb_total_free_inodes = &sbd->s_tinode; + sb->sv_bcache_count = &sbd->s_nfree; + sb->sv_bcache = &sbd->s_free[0]; + sb->sv_free_blocks = &sbd->s_tfree; + sb->sv_sb_time = &sbd->s_time; + sb->sv_sb_state = &sbd->s_state; + sb->sv_firstdatazone = fs16_to_cpu(sb, sbd->s_isize); + sb->sv_nzones = fs32_to_cpu(sb, sbd->s_fsize); +} + +static void detected_sysv2(struct super_block *sb) +{ + struct sysv2_super_block * sbd; + struct buffer_head *bh1 = sb->sv_bh1; + struct buffer_head *bh2 = sb->sv_bh2; + + if (bh1 == bh2) + sbd = (struct sysv2_super_block *) (bh1->b_data + BLOCK_SIZE/2); + else + sbd = (struct sysv2_super_block *) bh2->b_data; + + sb->sv_link_max = SYSV_LINK_MAX; + sb->sv_fic_size = SYSV_NICINOD; + sb->sv_flc_size = SYSV_NICFREE; + sb->sv_sbd1 = (char *) sbd; + sb->sv_sbd2 = (char *) sbd; + sb->sv_sb_fic_count = &sbd->s_ninode; + sb->sv_sb_fic_inodes = &sbd->s_inode[0]; + sb->sv_sb_total_free_inodes = &sbd->s_tinode; + sb->sv_bcache_count = &sbd->s_nfree; + sb->sv_bcache = &sbd->s_free[0]; + sb->sv_free_blocks = &sbd->s_tfree; + sb->sv_sb_time = &sbd->s_time; + sb->sv_sb_state = &sbd->s_state; + sb->sv_firstdatazone = fs16_to_cpu(sb, sbd->s_isize); + sb->sv_nzones = fs32_to_cpu(sb, sbd->s_fsize); +} + +static void detected_coherent(struct super_block *sb) +{ + struct coh_super_block * sbd; + struct buffer_head *bh1 = sb->sv_bh1; + + sbd = (struct coh_super_block *) bh1->b_data; + + sb->sv_link_max = COH_LINK_MAX; + sb->sv_fic_size = COH_NICINOD; + sb->sv_flc_size = COH_NICFREE; + sb->sv_sbd1 = (char *) sbd; + sb->sv_sbd2 = (char *) sbd; + sb->sv_sb_fic_count = &sbd->s_ninode; + sb->sv_sb_fic_inodes = &sbd->s_inode[0]; + sb->sv_sb_total_free_inodes = &sbd->s_tinode; + sb->sv_bcache_count = &sbd->s_nfree; + sb->sv_bcache = &sbd->s_free[0]; + sb->sv_free_blocks = &sbd->s_tfree; + sb->sv_sb_time = &sbd->s_time; + sb->sv_firstdatazone = fs16_to_cpu(sb, sbd->s_isize); + sb->sv_nzones = fs32_to_cpu(sb, sbd->s_fsize); +} + +static void detected_v7(struct super_block *sb) +{ + struct buffer_head *bh2 = sb->sv_bh2; + struct v7_super_block *sbd = (struct v7_super_block *)bh2->b_data; + + sb->sv_link_max = V7_LINK_MAX; + sb->sv_fic_size = V7_NICINOD; + sb->sv_flc_size = V7_NICFREE; + sb->sv_sbd1 = (char *)sbd; + sb->sv_sbd2 = (char *)sbd; + sb->sv_sb_fic_count = &sbd->s_ninode; + sb->sv_sb_fic_inodes = &sbd->s_inode[0]; + sb->sv_sb_total_free_inodes = &sbd->s_tinode; + sb->sv_bcache_count = &sbd->s_nfree; + sb->sv_bcache = &sbd->s_free[0]; + sb->sv_free_blocks = &sbd->s_tfree; + sb->sv_sb_time = &sbd->s_time; + sb->sv_firstdatazone = fs16_to_cpu(sb, sbd->s_isize); + sb->sv_nzones = fs32_to_cpu(sb, sbd->s_fsize); +} + +static int detect_xenix (struct super_block *sb, struct buffer_head *bh) +{ + struct xenix_super_block * sbd = (struct xenix_super_block *)bh->b_data; + if (sbd->s_magic == cpu_to_le32(0x2b5544)) + sb->sv_bytesex = BYTESEX_LE; + else if (sbd->s_magic == cpu_to_be32(0x2b5544)) + sb->sv_bytesex = BYTESEX_BE; + else + return 0; + if (sbd->s_type > 2 || sbd->s_type < 1) + return 0; + sb->sv_type = FSTYPE_XENIX; + return sbd->s_type; +} + +static int detect_sysv (struct super_block *sb, struct buffer_head *bh) +{ + /* All relevant fields are at the same offsets in R2 and R4 */ + struct sysv4_super_block * sbd; + + sbd = (struct sysv4_super_block *) (bh->b_data + BLOCK_SIZE/2); + if (sbd->s_magic == cpu_to_le32(0xfd187e20)) + sb->sv_bytesex = BYTESEX_LE; + else if (sbd->s_magic == cpu_to_be32(0xfd187e20)) + sb->sv_bytesex = BYTESEX_BE; + else + return 0; + if (sbd->s_time < JAN_1_1980) { + /* this is likely to happen on SystemV2 FS */ + if (sbd->s_type > 3 || sbd->s_type < 1) + return 0; + sb->sv_type = FSTYPE_SYSV2; + return sbd->s_type; + } + if ((sbd->s_type > 3 || sbd->s_type < 1) && + (sbd->s_type > 0x30 || sbd->s_type < 0x10)) + return 0; + + /* On Interactive Unix (ISC) Version 4.0/3.x s_type field = 0x10, + 0x20 or 0x30 indicates that symbolic links and the 14-character + filename limit is gone. Due to lack of information about this + feature read-only mode seems to be a reasonable approach... -KGB */ + + if (sbd->s_type >= 0x10) { + printk("SysV FS: can't handle long file names on %s, " + "forcing read-only mode.\n", kdevname(sb->s_dev)); + sb->s_flags |= MS_RDONLY; + } + + sb->sv_type = FSTYPE_SYSV4; + return sbd->s_type >= 0x10 ? (sbd->s_type >> 4) : sbd->s_type; +} + +static int detect_coherent (struct super_block *sb, struct buffer_head *bh) +{ + struct coh_super_block * sbd; + + sbd = (struct coh_super_block *) (bh->b_data + BLOCK_SIZE/2); + if ((memcmp(sbd->s_fname,"noname",6) && memcmp(sbd->s_fname,"xxxxx ",6)) + || (memcmp(sbd->s_fpack,"nopack",6) && memcmp(sbd->s_fpack,"xxxxx\n",6))) + return 0; + sb->sv_bytesex = BYTESEX_PDP; + sb->sv_type = FSTYPE_COH; + return 1; +} + +static int detect_sysv_odd(struct super_block *sb, struct buffer_head *bh) +{ + int size = detect_sysv(sb, bh); + + return size>2 ? 0 : size; +} + +static struct { + int block; + int (*test)(struct super_block *, struct buffer_head *); +} flavours[] = { + {1, detect_xenix}, + {0, detect_sysv}, + {0, detect_coherent}, + {9, detect_sysv_odd}, + {15,detect_sysv_odd}, + {18,detect_sysv}, +}; + +static char *flavour_names[] = { + [FSTYPE_XENIX] "Xenix", + [FSTYPE_SYSV4] "SystemV", + [FSTYPE_SYSV2] "SystemV Release 2", + [FSTYPE_COH] "Coherent", + [FSTYPE_V7] "V7", +}; + +static void (*flavour_setup[])(struct super_block *) = { + [FSTYPE_XENIX] detected_xenix, + [FSTYPE_SYSV4] detected_sysv4, + [FSTYPE_SYSV2] detected_sysv2, + [FSTYPE_COH] detected_coherent, + [FSTYPE_V7] detected_v7, +}; + +static int complete_read_super(struct super_block *sb, int silent, int size) +{ + struct inode *root_inode; + char *found = flavour_names[sb->sv_type]; + u_char n_bits = size+8; + int bsize = 1 << n_bits; + int bsize_4 = bsize >> 2; + + sb->sv_kludge_symlinks = 1; + sb->sv_firstinodezone = 2; + + flavour_setup[sb->sv_type](sb); + + sb->sv_truncate = 1; + sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone; + sb->sv_inodes_per_block = bsize >> 6; + sb->sv_inodes_per_block_1 = (bsize >> 6)-1; + sb->sv_inodes_per_block_bits = n_bits-6; + sb->sv_ind_per_block = bsize_4; + sb->sv_ind_per_block_2 = bsize_4*bsize_4; + sb->sv_toobig_block = 10 + bsize_4 * (1 + bsize_4 * (1 + bsize_4)); + sb->sv_ind_per_block_bits = n_bits-2; + + sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone) << sb->sv_inodes_per_block_bits; + + sb->s_blocksize = bsize; + sb->s_blocksize_bits = n_bits; + if (!silent) + printk("VFS: Found a %s FS (block size = %ld) on device %s\n", + found, sb->s_blocksize, bdevname(sb->s_dev)); + + sb->s_magic = SYSV_MAGIC_BASE + sb->sv_type; + /* set up enough so that it can read an inode */ + sb->s_op = &sysv_sops; + root_inode = iget(sb,SYSV_ROOT_INO); + if (!root_inode) { + printk("SysV FS: get root inode failed\n"); + return 0; + } + sb->s_root = d_alloc_root(root_inode); + if (!sb->s_root) { + iput(root_inode); + printk("SysV FS: get root dentry failed\n"); + return 0; + } + if (sb->sv_truncate) + sb->s_root->d_op = &sysv_dentry_operations; + sb->s_flags |= MS_RDONLY; + sb->s_dirt = 1; + return 1; +} + +static struct super_block *sysv_read_super(struct super_block *sb, + void *data, int silent) +{ + struct buffer_head *bh1; + struct buffer_head *bh = NULL; + kdev_t dev = sb->s_dev; + unsigned long blocknr; + int size = 0; + int i; + + if (1024 != sizeof (struct xenix_super_block)) + panic("Xenix FS: bad super-block size"); + if ((512 != sizeof (struct sysv4_super_block)) + || (512 != sizeof (struct sysv2_super_block))) + panic("SystemV FS: bad super-block size"); + if (500 != sizeof (struct coh_super_block)) + panic("Coherent FS: bad super-block size"); + if (64 != sizeof (struct sysv_inode)) + panic("sysv fs: bad i-node size"); + set_blocksize(dev,BLOCK_SIZE); + sb->sv_block_base = 0; + + for (i = 0; i < sizeof(flavours)/sizeof(flavours[0]) && !size; i++) { + struct buffer_head *next_bh; + next_bh = bread(dev, flavours[i].block, BLOCK_SIZE); + if (!next_bh) + continue; + brelse(bh); + bh = next_bh; + + size = flavours[i].test(sb, bh); + } + + if (!size) + goto Eunknown; + + switch (size) { + case 1: + blocknr = bh->b_blocknr << 1; + brelse(bh); + set_blocksize(dev, 512); + bh1 = bread(dev, blocknr, 512); + bh = bread(dev, blocknr + 1, 512); + break; + case 2: + bh1 = bh; + break; + case 3: + blocknr = bh->b_blocknr >> 1; + brelse(bh); + set_blocksize(dev, 2048); + bh1 = bh = bread(dev, blocknr, 2048); + break; + default: + goto Ebadsize; + } + + if (bh && bh1) { + sb->sv_bh1 = bh1; + sb->sv_bh2 = bh; + if (complete_read_super(sb, silent, size)) + return sb; + } + + brelse(bh1); + brelse(bh); + set_blocksize(sb->s_dev,BLOCK_SIZE); + printk("oldfs: cannot read superblock\n"); +failed: + return NULL; + +Eunknown: + brelse(bh); + if (!silent) + printk("VFS: unable to find oldfs superblock on device %s\n", + bdevname(dev)); + goto failed; +Ebadsize: + brelse(bh); + if (!silent) + printk("VFS: oldfs: unsupported block size (%dKb)\n", + 1<<(size-2)); + goto failed; +} + +static struct super_block *v7_read_super(struct super_block *sb,void *data, + int silent) +{ + struct buffer_head *bh; + kdev_t dev = sb->s_dev; + + if (440 != sizeof (struct v7_super_block)) + panic("V7 FS: bad super-block size"); + if (64 != sizeof (struct sysv_inode)) + panic("sysv fs: bad i-node size"); + + sb->sv_type = FSTYPE_V7; + sb->sv_bytesex = BYTESEX_PDP; + + set_blocksize(dev,512); + + if ((bh = bread(dev, 1, 512)) == NULL) { + if (!silent) + printk("VFS: unable to read V7 FS superblock on device " + "%s.\n", bdevname(dev)); + goto failed; + } + + + sb->sv_bh1 = bh; + sb->sv_bh2 = bh; + if (complete_read_super(sb, silent, 1)) + return sb; + + brelse(bh); +failed: + return NULL; +} + +/* Every kernel module contains stuff like this. */ + +static DECLARE_FSTYPE_DEV(sysv_fs_type, "sysv", sysv_read_super); +static DECLARE_FSTYPE_DEV(v7_fs_type, "v7", v7_read_super); + +static int __init init_sysv_fs(void) +{ + int err = register_filesystem(&sysv_fs_type); + if (!err) + err = register_filesystem(&v7_fs_type); + return err; +} + +static void __exit exit_sysv_fs(void) +{ + unregister_filesystem(&sysv_fs_type); + unregister_filesystem(&v7_fs_type); +} + +EXPORT_NO_SYMBOLS; + +module_init(init_sysv_fs) +module_exit(exit_sysv_fs) diff --git a/fs/sysv/truncate.c b/fs/sysv/truncate.c deleted file mode 100644 index 559af828d450..000000000000 --- a/fs/sysv/truncate.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * linux/fs/sysv/truncate.c - * - * minix/truncate.c - * Copyright (C) 1991, 1992 Linus Torvalds - * - * coh/truncate.c - * Copyright (C) 1993 Pascal Haible, Bruno Haible - * - * sysv/truncate.c - * Copyright (C) 1993 Bruno Haible - */ - -#include <linux/sched.h> -#include <linux/fs.h> -#include <linux/sysv_fs.h> -#include <linux/stat.h> - - -/* Linus' implementation of truncate. - * It doesn't need locking because it can tell from looking at bh->b_count - * whether a given block is in use elsewhere. - */ - -/* - * Truncate has the most races in the whole filesystem: coding it is - * a pain in the a**, especially as I don't do any locking. - * - * The code may look a bit weird, but that's just because I've tried to - * handle things like file-size changes in a somewhat graceful manner. - * Anyway, truncating a file at the same time somebody else writes to it - * is likely to result in pretty weird behaviour... - * - * The new code handles normal truncates (size = 0) as well as the more - * general case (size = XXX). I hope. - */ - -#define DATA_BUFFER_USED(bh) \ - (atomic_read(&bh->b_count)>1 || buffer_locked(bh)) - -/* We throw away any data beyond inode->i_size. */ - -static int trunc_direct(struct inode * inode) -{ - struct super_block * sb; - unsigned int i; - u32 * p; - u32 block; - struct buffer_head * bh; - int retry = 0; - - sb = inode->i_sb; -repeat: - for (i = ((unsigned long) inode->i_size + sb->sv_block_size_1) >> sb->sv_block_size_bits; i < 10; i++) { - p = inode->u.sysv_i.i_data + i; - block = *p; - if (!block) - continue; - bh = sv_get_hash_table(sb, inode->i_dev, block); - if ((i << sb->sv_block_size_bits) < inode->i_size) { - brelse(bh); - goto repeat; - } - if ((bh && DATA_BUFFER_USED(bh)) || (block != *p)) { - retry = 1; - brelse(bh); - continue; - } - *p = 0; - mark_inode_dirty(inode); - brelse(bh); - sysv_free_block(sb,block); - } - return retry; -} - -static int trunc_indirect(struct inode * inode, unsigned long offset, sysv_zone_t * p, int convert, unsigned char * dirt) -{ - unsigned long indtmp, indblock; - struct super_block * sb; - struct buffer_head * indbh; - unsigned int i; - sysv_zone_t * ind; - unsigned long tmp, block; - struct buffer_head * bh; - int retry = 0; - - indblock = indtmp = *p; - if (convert) - indblock = from_coh_ulong(indblock); - if (!indblock) - return 0; - sb = inode->i_sb; - indbh = sv_bread(sb, inode->i_dev, indblock); - if (indtmp != *p) { - brelse(indbh); - return 1; - } - if (!indbh) { - *p = 0; - *dirt = 1; - return 0; - } -repeat: - if (inode->i_size < offset) - i = 0; - else - i = (inode->i_size - offset + sb->sv_block_size_1) >> sb->sv_block_size_bits; - for (; i < sb->sv_ind_per_block; i++) { - ind = ((sysv_zone_t *) indbh->b_data) + i; - block = tmp = *ind; - if (sb->sv_convert) - block = from_coh_ulong(block); - if (!block) - continue; - bh = sv_get_hash_table(sb, inode->i_dev, block); - if ((i << sb->sv_block_size_bits) + offset < inode->i_size) { - brelse(bh); - goto repeat; - } - if ((bh && DATA_BUFFER_USED(bh)) || (tmp != *ind)) { - retry = 1; - brelse(bh); - continue; - } - *ind = 0; - mark_buffer_dirty(indbh); - brelse(bh); - sysv_free_block(sb,block); - } - for (i = 0; i < sb->sv_ind_per_block; i++) - if (((sysv_zone_t *) indbh->b_data)[i]) - goto done; - if (DATA_BUFFER_USED(indbh) || (indtmp != *p)) { - brelse(indbh); - return 1; - } - *p = 0; - *dirt = 1; - sysv_free_block(sb,indblock); -done: - brelse(indbh); - return retry; -} - -static int trunc_dindirect(struct inode * inode, unsigned long offset, sysv_zone_t * p, int convert, unsigned char * dirt) -{ - u32 indtmp, indblock; - struct super_block * sb; - struct buffer_head * indbh; - unsigned int i; - sysv_zone_t * ind; - u32 tmp, block; - int retry = 0; - - indblock = indtmp = *p; - if (convert) - indblock = from_coh_ulong(indblock); - if (!indblock) - return 0; - sb = inode->i_sb; - indbh = sv_bread(sb, inode->i_dev, indblock); - if (indtmp != *p) { - brelse(indbh); - return 1; - } - if (!indbh) { - *p = 0; - *dirt = 1; - return 0; - } - if (inode->i_size < offset) - i = 0; - else - i = (inode->i_size - offset + sb->sv_ind_per_block_block_size_1) >> sb->sv_ind_per_block_block_size_bits; - for (; i < sb->sv_ind_per_block; i++) { - unsigned char dirty = 0; - ind = ((sysv_zone_t *) indbh->b_data) + i; - block = tmp = *ind; - if (sb->sv_convert) - block = from_coh_ulong(block); - if (!block) - continue; - retry |= trunc_indirect(inode,offset+(i<<sb->sv_ind_per_block_bits),ind,sb->sv_convert,&dirty); - if (dirty) - mark_buffer_dirty(indbh); - } - for (i = 0; i < sb->sv_ind_per_block; i++) - if (((sysv_zone_t *) indbh->b_data)[i]) - goto done; - if (DATA_BUFFER_USED(indbh) || (indtmp != *p)) { - brelse(indbh); - return 1; - } - *p = 0; - *dirt = 1; - sysv_free_block(sb,indblock); -done: - brelse(indbh); - return retry; -} - -static int trunc_tindirect(struct inode * inode, unsigned long offset, sysv_zone_t * p, int convert, unsigned char * dirt) -{ - u32 indtmp, indblock; - struct super_block * sb; - struct buffer_head * indbh; - unsigned int i; - sysv_zone_t * ind; - u32 tmp, block; - int retry = 0; - - indblock = indtmp = *p; - if (convert) - indblock = from_coh_ulong(indblock); - if (!indblock) - return 0; - sb = inode->i_sb; - indbh = sv_bread(sb, inode->i_dev, indblock); - if (indtmp != *p) { - brelse(indbh); - return 1; - } - if (!indbh) { - *p = 0; - *dirt = 1; - return 0; - } - if (inode->i_size < offset) - i = 0; - else - i = (inode->i_size - offset + sb->sv_ind_per_block_2_block_size_1) >> sb->sv_ind_per_block_2_block_size_bits; - for (; i < sb->sv_ind_per_block; i++) { - unsigned char dirty = 0; - ind = ((sysv_zone_t *) indbh->b_data) + i; - block = tmp = *ind; - if (sb->sv_convert) - block = from_coh_ulong(block); - if (!block) - continue; - retry |= trunc_dindirect(inode,offset+(i<<sb->sv_ind_per_block_2_bits),ind,sb->sv_convert,&dirty); - if (dirty) - mark_buffer_dirty(indbh); - } - for (i = 0; i < sb->sv_ind_per_block; i++) - if (((sysv_zone_t *) indbh->b_data)[i]) - goto done; - if (DATA_BUFFER_USED(indbh) || (indtmp != *p)) { - brelse(indbh); - return 1; - } - *p = 0; - *dirt = 1; - sysv_free_block(sb,indblock); -done: - brelse(indbh); - return retry; -} - -static int trunc_all(struct inode * inode) -{ - struct super_block * sb; - char dirty; - - sb = inode->i_sb; - return trunc_direct(inode) - | trunc_indirect(inode,sb->sv_ind0_size,&inode->u.sysv_i.i_data[10],0,&dirty) - | trunc_dindirect(inode,sb->sv_ind1_size,&inode->u.sysv_i.i_data[11],0,&dirty) - | trunc_tindirect(inode,sb->sv_ind2_size,&inode->u.sysv_i.i_data[12],0,&dirty); -} - - -void sysv_truncate(struct inode * inode) -{ - /* If this is called from sysv_put_inode, we needn't worry about - * races as we are just losing the last reference to the inode. - * If this is called from another place, let's hope it's a regular - * file. - * Truncating symbolic links is strange. We assume we don't truncate - * a directory we are just modifying. We ensure we don't truncate - * a regular file we are just writing to, by use of a lock. - */ - if (S_ISLNK(inode->i_mode)) - printk("sysv_truncate: truncating symbolic link\n"); - else if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) - return; - while (trunc_all(inode)) { - current->counter = 0; - schedule(); - } - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); -} diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c index 29d835b5d02a..bd2c3ae7a71a 100644 --- a/fs/udf/ialloc.c +++ b/fs/udf/ialloc.c @@ -144,8 +144,10 @@ struct inode * udf_new_inode (const struct inode *dir, int mode, int * err) UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_SHORT; else UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG; - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - UDF_I_UMTIME(inode) = UDF_I_UATIME(inode) = UDF_I_UCTIME(inode) = CURRENT_UTIME; + inode->i_mtime = inode->i_atime = inode->i_ctime = + UDF_I_CRTIME(inode) = CURRENT_TIME; + UDF_I_UMTIME(inode) = UDF_I_UCTIME(inode) = + UDF_I_UCRTIME(inode) = CURRENT_UTIME; UDF_I_NEW_INODE(inode) = 1; insert_inode_hash(inode); mark_inode_dirty(inode); diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 47c94c6a68fa..ff919240c212 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -203,7 +203,6 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err) UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_SHORT; else UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG; - inode->i_blocks = inode->i_sb->s_blocksize / 512; mark_buffer_dirty_inode(bh, inode); udf_release_data(bh); @@ -1080,31 +1079,37 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) (inode->i_sb->s_blocksize_bits - 9); if ( udf_stamp_to_time(&convtime, &convtime_usec, + lets_to_cpu(fe->accessTime)) ) + { + inode->i_atime = convtime; + } + else + { + inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb); + } + + if ( udf_stamp_to_time(&convtime, &convtime_usec, lets_to_cpu(fe->modificationTime)) ) { inode->i_mtime = convtime; UDF_I_UMTIME(inode) = convtime_usec; - inode->i_ctime = convtime; - UDF_I_UCTIME(inode) = convtime_usec; } else { inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb); UDF_I_UMTIME(inode) = 0; - inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb); - UDF_I_UCTIME(inode) = 0; } if ( udf_stamp_to_time(&convtime, &convtime_usec, - lets_to_cpu(fe->accessTime)) ) + lets_to_cpu(fe->attrTime)) ) { - inode->i_atime = convtime; - UDF_I_UATIME(inode) = convtime_usec; + inode->i_ctime = convtime; + UDF_I_UCTIME(inode) = convtime_usec; } else { - inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb); - UDF_I_UATIME(inode) = convtime_usec; + inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb); + UDF_I_UCTIME(inode) = 0; } UDF_I_UNIQUE(inode) = le64_to_cpu(fe->uniqueID); @@ -1119,6 +1124,16 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) (inode->i_sb->s_blocksize_bits - 9); if ( udf_stamp_to_time(&convtime, &convtime_usec, + lets_to_cpu(efe->accessTime)) ) + { + inode->i_atime = convtime; + } + else + { + inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb); + } + + if ( udf_stamp_to_time(&convtime, &convtime_usec, lets_to_cpu(efe->modificationTime)) ) { inode->i_mtime = convtime; @@ -1131,19 +1146,19 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) } if ( udf_stamp_to_time(&convtime, &convtime_usec, - lets_to_cpu(efe->accessTime)) ) + lets_to_cpu(efe->createTime)) ) { - inode->i_atime = convtime; - UDF_I_UATIME(inode) = convtime_usec; + UDF_I_CRTIME(inode) = convtime; + UDF_I_UCRTIME(inode) = convtime_usec; } else { - inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb); - UDF_I_UATIME(inode) = 0; + UDF_I_CRTIME(inode) = UDF_SB_RECORDTIME(inode->i_sb); + UDF_I_UCRTIME(inode) = 0; } if ( udf_stamp_to_time(&convtime, &convtime_usec, - lets_to_cpu(efe->createTime)) ) + lets_to_cpu(efe->attrTime)) ) { inode->i_ctime = convtime; UDF_I_UCTIME(inode) = convtime_usec; @@ -1171,6 +1186,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) inode->i_nlink ++; break; } + case FILE_TYPE_REALTIME: case FILE_TYPE_REGULAR: case FILE_TYPE_NONE: { @@ -1399,13 +1415,12 @@ udf_update_inode(struct inode *inode, int do_sync) (inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >> (inode->i_sb->s_blocksize_bits - 9)); - if (udf_time_to_stamp(&cpu_time, inode->i_atime, UDF_I_UATIME(inode))) + if (udf_time_to_stamp(&cpu_time, inode->i_atime, 0)) fe->accessTime = cpu_to_lets(cpu_time); if (udf_time_to_stamp(&cpu_time, inode->i_mtime, UDF_I_UMTIME(inode))) - { fe->modificationTime = cpu_to_lets(cpu_time); + if (udf_time_to_stamp(&cpu_time, inode->i_ctime, UDF_I_UCTIME(inode))) fe->attrTime = cpu_to_lets(cpu_time); - } memset(&(fe->impIdent), 0, sizeof(EntityID)); strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER); fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; @@ -1418,19 +1433,40 @@ udf_update_inode(struct inode *inode, int do_sync) } else { + efe->objectSize = cpu_to_le64(inode->i_size); efe->logicalBlocksRecorded = cpu_to_le64( - (inode->i_blocks + (2 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >> + (inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >> (inode->i_sb->s_blocksize_bits - 9)); - if (udf_time_to_stamp(&cpu_time, inode->i_atime, UDF_I_UATIME(inode))) + if (UDF_I_CRTIME(inode) >= inode->i_atime) + { + UDF_I_CRTIME(inode) = inode->i_atime; + UDF_I_UCRTIME(inode) = 0; + } + if (UDF_I_CRTIME(inode) > inode->i_mtime || + (UDF_I_CRTIME(inode) == inode->i_mtime && + UDF_I_UCRTIME(inode) > UDF_I_UMTIME(inode))) + { + UDF_I_CRTIME(inode) = inode->i_mtime; + UDF_I_UCRTIME(inode) = UDF_I_UMTIME(inode); + } + if (UDF_I_CRTIME(inode) > inode->i_ctime || + (UDF_I_CRTIME(inode) == inode->i_ctime && + UDF_I_UCRTIME(inode) > UDF_I_UCTIME(inode))) + { + UDF_I_CRTIME(inode) = inode->i_ctime; + UDF_I_UCRTIME(inode) = UDF_I_UCTIME(inode); + } + + if (udf_time_to_stamp(&cpu_time, inode->i_atime, 0)) efe->accessTime = cpu_to_lets(cpu_time); if (udf_time_to_stamp(&cpu_time, inode->i_mtime, UDF_I_UMTIME(inode))) efe->modificationTime = cpu_to_lets(cpu_time); - if (udf_time_to_stamp(&cpu_time, inode->i_ctime, UDF_I_UCTIME(inode))) - { + if (udf_time_to_stamp(&cpu_time, UDF_I_CRTIME(inode), UDF_I_UCRTIME(inode))) efe->createTime = cpu_to_lets(cpu_time); + if (udf_time_to_stamp(&cpu_time, inode->i_ctime, UDF_I_UCTIME(inode))) efe->attrTime = cpu_to_lets(cpu_time); - } + memset(&(efe->impIdent), 0, sizeof(EntityID)); strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER); efe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h index fdaf8c28e502..8ffa2f316adc 100644 --- a/fs/udf/udf_i.h +++ b/fs/udf/udf_i.h @@ -14,8 +14,9 @@ #define UDF_I_NEW_INODE(X) ( UDF_I(X)->i_new_inode ) #define UDF_I_NEXT_ALLOC_BLOCK(X) ( UDF_I(X)->i_next_alloc_block ) #define UDF_I_NEXT_ALLOC_GOAL(X) ( UDF_I(X)->i_next_alloc_goal ) -#define UDF_I_UATIME(X) ( UDF_I(X)->i_uatime ) #define UDF_I_UMTIME(X) ( UDF_I(X)->i_umtime ) #define UDF_I_UCTIME(X) ( UDF_I(X)->i_uctime ) +#define UDF_I_CRTIME(X) ( UDF_I(X)->i_crtime ) +#define UDF_I_UCRTIME(X) ( UDF_I(X)->i_ucrtime ) #endif /* !defined(_LINUX_UDF_I_H) */ diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h index c8d826232e19..9b14bcf6c95e 100644 --- a/include/asm-i386/elf.h +++ b/include/asm-i386/elf.h @@ -55,7 +55,7 @@ typedef struct user_fxsr_struct elf_fpxregset_t; the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ -#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) +#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) /* Wow, the "main" arch needs arch dependent functions too.. :) */ diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h index ec4823866cb9..74c43e03f00e 100644 --- a/include/asm-i386/uaccess.h +++ b/include/asm-i386/uaccess.h @@ -129,12 +129,6 @@ extern void __put_user_4(void); extern void __put_user_bad(void); -#define __put_user_x(size,ret,x,ptr) \ - __asm__ __volatile__("call __put_user_" #size \ - :"=a" (ret) \ - :"0" (ptr),"d" (x) \ - :"cx") - #define put_user(x,ptr) \ __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) diff --git a/include/asm-mips/addrspace.h b/include/asm-mips/addrspace.h index 39259486e6fa..0d1bf3246db0 100644 --- a/include/asm-mips/addrspace.h +++ b/include/asm-mips/addrspace.h @@ -4,6 +4,7 @@ * for more details. * * Copyright (C) 1996 by Ralf Baechle + * Copyright (C) 2000 by Maciej W. Rozycki * * Defitions for the address spaces of the MIPS CPUs. */ @@ -19,23 +20,40 @@ #define KSEG2 0xc0000000 #define KSEG3 0xe0000000 +#define K0BASE KSEG0 + /* * Returns the kernel segment base of a given address */ +#ifndef __ASSEMBLY__ #define KSEGX(a) (((unsigned long)(a)) & 0xe0000000) +#else +#define KSEGX(a) ((a) & 0xe0000000) +#endif /* * Returns the physical address of a KSEG0/KSEG1 address */ +#ifndef __ASSEMBLY__ #define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff) +#else +#define PHYSADDR(a) ((a) & 0x1fffffff) +#endif /* * Map an address to a certain kernel segment */ +#ifndef __ASSEMBLY__ #define KSEG0ADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG0)) #define KSEG1ADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG1)) #define KSEG2ADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG2)) #define KSEG3ADDR(a) ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG3)) +#else +#define KSEG0ADDR(a) (((a) & 0x1fffffff) | KSEG0) +#define KSEG1ADDR(a) (((a) & 0x1fffffff) | KSEG1) +#define KSEG2ADDR(a) (((a) & 0x1fffffff) | KSEG2) +#define KSEG3ADDR(a) (((a) & 0x1fffffff) | KSEG3) +#endif /* * Memory segments (64bit kernel mode addresses) diff --git a/include/asm-mips/asmmacro.h b/include/asm-mips/asmmacro.h index fb3692dd705c..7becc9bd1ae2 100644 --- a/include/asm-mips/asmmacro.h +++ b/include/asm-mips/asmmacro.h @@ -3,124 +3,122 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * Copyright (C) 1998 Ralf Baechle - * - * $Id: asmmacro.h,v 1.3 1998/03/27 04:47:58 ralf Exp $ */ -#ifndef __MIPS_ASMMACRO_H -#define __MIPS_ASMMACRO_H +#ifndef _ASM_ASMMACRO_H +#define _ASM_ASMMACRO_H #include <asm/offset.h> #define FPU_SAVE_DOUBLE(thread, tmp) \ cfc1 tmp, fcr31; \ sdc1 $f0, (THREAD_FPU + 0x000)(thread); \ - sdc1 $f2, (THREAD_FPU + 0x008)(thread); \ - sdc1 $f4, (THREAD_FPU + 0x010)(thread); \ - sdc1 $f6, (THREAD_FPU + 0x018)(thread); \ - sdc1 $f8, (THREAD_FPU + 0x020)(thread); \ - sdc1 $f10, (THREAD_FPU + 0x028)(thread); \ - sdc1 $f12, (THREAD_FPU + 0x030)(thread); \ - sdc1 $f14, (THREAD_FPU + 0x038)(thread); \ - sdc1 $f16, (THREAD_FPU + 0x040)(thread); \ - sdc1 $f18, (THREAD_FPU + 0x048)(thread); \ - sdc1 $f20, (THREAD_FPU + 0x050)(thread); \ - sdc1 $f22, (THREAD_FPU + 0x058)(thread); \ - sdc1 $f24, (THREAD_FPU + 0x060)(thread); \ - sdc1 $f26, (THREAD_FPU + 0x068)(thread); \ - sdc1 $f28, (THREAD_FPU + 0x070)(thread); \ - sdc1 $f30, (THREAD_FPU + 0x078)(thread); \ - sw tmp, (THREAD_FPU + 0x080)(thread) + sdc1 $f2, (THREAD_FPU + 0x010)(thread); \ + sdc1 $f4, (THREAD_FPU + 0x020)(thread); \ + sdc1 $f6, (THREAD_FPU + 0x030)(thread); \ + sdc1 $f8, (THREAD_FPU + 0x040)(thread); \ + sdc1 $f10, (THREAD_FPU + 0x050)(thread); \ + sdc1 $f12, (THREAD_FPU + 0x060)(thread); \ + sdc1 $f14, (THREAD_FPU + 0x070)(thread); \ + sdc1 $f16, (THREAD_FPU + 0x080)(thread); \ + sdc1 $f18, (THREAD_FPU + 0x090)(thread); \ + sdc1 $f20, (THREAD_FPU + 0x0a0)(thread); \ + sdc1 $f22, (THREAD_FPU + 0x0b0)(thread); \ + sdc1 $f24, (THREAD_FPU + 0x0c0)(thread); \ + sdc1 $f26, (THREAD_FPU + 0x0d0)(thread); \ + sdc1 $f28, (THREAD_FPU + 0x0e0)(thread); \ + sdc1 $f30, (THREAD_FPU + 0x0f0)(thread); \ + sw tmp, (THREAD_FPU + 0x100)(thread) #define FPU_SAVE_SINGLE(thread,tmp) \ cfc1 tmp, fcr31; \ swc1 $f0, (THREAD_FPU + 0x000)(thread); \ - swc1 $f1, (THREAD_FPU + 0x004)(thread); \ - swc1 $f2, (THREAD_FPU + 0x008)(thread); \ - swc1 $f3, (THREAD_FPU + 0x00c)(thread); \ - swc1 $f4, (THREAD_FPU + 0x010)(thread); \ - swc1 $f5, (THREAD_FPU + 0x014)(thread); \ - swc1 $f6, (THREAD_FPU + 0x018)(thread); \ - swc1 $f7, (THREAD_FPU + 0x01c)(thread); \ - swc1 $f8, (THREAD_FPU + 0x020)(thread); \ - swc1 $f9, (THREAD_FPU + 0x024)(thread); \ - swc1 $f10, (THREAD_FPU + 0x028)(thread); \ - swc1 $f11, (THREAD_FPU + 0x02c)(thread); \ - swc1 $f12, (THREAD_FPU + 0x030)(thread); \ - swc1 $f13, (THREAD_FPU + 0x034)(thread); \ - swc1 $f14, (THREAD_FPU + 0x038)(thread); \ - swc1 $f15, (THREAD_FPU + 0x03c)(thread); \ - swc1 $f16, (THREAD_FPU + 0x040)(thread); \ - swc1 $f17, (THREAD_FPU + 0x044)(thread); \ - swc1 $f18, (THREAD_FPU + 0x048)(thread); \ - swc1 $f19, (THREAD_FPU + 0x04c)(thread); \ - swc1 $f20, (THREAD_FPU + 0x050)(thread); \ - swc1 $f21, (THREAD_FPU + 0x054)(thread); \ - swc1 $f22, (THREAD_FPU + 0x058)(thread); \ - swc1 $f23, (THREAD_FPU + 0x05c)(thread); \ - swc1 $f24, (THREAD_FPU + 0x060)(thread); \ - swc1 $f25, (THREAD_FPU + 0x064)(thread); \ - swc1 $f26, (THREAD_FPU + 0x068)(thread); \ - swc1 $f27, (THREAD_FPU + 0x06c)(thread); \ - swc1 $f28, (THREAD_FPU + 0x070)(thread); \ - swc1 $f29, (THREAD_FPU + 0x074)(thread); \ - swc1 $f30, (THREAD_FPU + 0x078)(thread); \ - swc1 $f31, (THREAD_FPU + 0x07c)(thread); \ - sw tmp, (THREAD_FPU + 0x080)(thread) + swc1 $f1, (THREAD_FPU + 0x008)(thread); \ + swc1 $f2, (THREAD_FPU + 0x010)(thread); \ + swc1 $f3, (THREAD_FPU + 0x018)(thread); \ + swc1 $f4, (THREAD_FPU + 0x020)(thread); \ + swc1 $f5, (THREAD_FPU + 0x028)(thread); \ + swc1 $f6, (THREAD_FPU + 0x030)(thread); \ + swc1 $f7, (THREAD_FPU + 0x038)(thread); \ + swc1 $f8, (THREAD_FPU + 0x040)(thread); \ + swc1 $f9, (THREAD_FPU + 0x048)(thread); \ + swc1 $f10, (THREAD_FPU + 0x050)(thread); \ + swc1 $f11, (THREAD_FPU + 0x058)(thread); \ + swc1 $f12, (THREAD_FPU + 0x060)(thread); \ + swc1 $f13, (THREAD_FPU + 0x068)(thread); \ + swc1 $f14, (THREAD_FPU + 0x070)(thread); \ + swc1 $f15, (THREAD_FPU + 0x078)(thread); \ + swc1 $f16, (THREAD_FPU + 0x080)(thread); \ + swc1 $f17, (THREAD_FPU + 0x088)(thread); \ + swc1 $f18, (THREAD_FPU + 0x090)(thread); \ + swc1 $f19, (THREAD_FPU + 0x098)(thread); \ + swc1 $f20, (THREAD_FPU + 0x0a0)(thread); \ + swc1 $f21, (THREAD_FPU + 0x0a8)(thread); \ + swc1 $f22, (THREAD_FPU + 0x0b0)(thread); \ + swc1 $f23, (THREAD_FPU + 0x0b8)(thread); \ + swc1 $f24, (THREAD_FPU + 0x0c0)(thread); \ + swc1 $f25, (THREAD_FPU + 0x0c8)(thread); \ + swc1 $f26, (THREAD_FPU + 0x0d0)(thread); \ + swc1 $f27, (THREAD_FPU + 0x0d8)(thread); \ + swc1 $f28, (THREAD_FPU + 0x0e0)(thread); \ + swc1 $f29, (THREAD_FPU + 0x0e8)(thread); \ + swc1 $f30, (THREAD_FPU + 0x0f0)(thread); \ + swc1 $f31, (THREAD_FPU + 0x0f8)(thread); \ + sw tmp, (THREAD_FPU + 0x100)(thread) #define FPU_RESTORE_DOUBLE(thread, tmp) \ - lw tmp, (THREAD_FPU + 0x080)(thread); \ + lw tmp, (THREAD_FPU + 0x100)(thread); \ ldc1 $f0, (THREAD_FPU + 0x000)(thread); \ - ldc1 $f2, (THREAD_FPU + 0x008)(thread); \ - ldc1 $f4, (THREAD_FPU + 0x010)(thread); \ - ldc1 $f6, (THREAD_FPU + 0x018)(thread); \ - ldc1 $f8, (THREAD_FPU + 0x020)(thread); \ - ldc1 $f10, (THREAD_FPU + 0x028)(thread); \ - ldc1 $f12, (THREAD_FPU + 0x030)(thread); \ - ldc1 $f14, (THREAD_FPU + 0x038)(thread); \ - ldc1 $f16, (THREAD_FPU + 0x040)(thread); \ - ldc1 $f18, (THREAD_FPU + 0x048)(thread); \ - ldc1 $f20, (THREAD_FPU + 0x050)(thread); \ - ldc1 $f22, (THREAD_FPU + 0x058)(thread); \ - ldc1 $f24, (THREAD_FPU + 0x060)(thread); \ - ldc1 $f26, (THREAD_FPU + 0x068)(thread); \ - ldc1 $f28, (THREAD_FPU + 0x070)(thread); \ - ldc1 $f30, (THREAD_FPU + 0x078)(thread); \ + ldc1 $f2, (THREAD_FPU + 0x010)(thread); \ + ldc1 $f4, (THREAD_FPU + 0x020)(thread); \ + ldc1 $f6, (THREAD_FPU + 0x030)(thread); \ + ldc1 $f8, (THREAD_FPU + 0x040)(thread); \ + ldc1 $f10, (THREAD_FPU + 0x050)(thread); \ + ldc1 $f12, (THREAD_FPU + 0x060)(thread); \ + ldc1 $f14, (THREAD_FPU + 0x070)(thread); \ + ldc1 $f16, (THREAD_FPU + 0x080)(thread); \ + ldc1 $f18, (THREAD_FPU + 0x090)(thread); \ + ldc1 $f20, (THREAD_FPU + 0x0a0)(thread); \ + ldc1 $f22, (THREAD_FPU + 0x0b0)(thread); \ + ldc1 $f24, (THREAD_FPU + 0x0c0)(thread); \ + ldc1 $f26, (THREAD_FPU + 0x0d0)(thread); \ + ldc1 $f28, (THREAD_FPU + 0x0e0)(thread); \ + ldc1 $f30, (THREAD_FPU + 0x0f0)(thread); \ ctc1 tmp, fcr31 #define FPU_RESTORE_SINGLE(thread,tmp) \ - lw tmp, (THREAD_FPU + 0x080)(thread); \ + lw tmp, (THREAD_FPU + 0x100)(thread); \ lwc1 $f0, (THREAD_FPU + 0x000)(thread); \ - lwc1 $f1, (THREAD_FPU + 0x004)(thread); \ - lwc1 $f2, (THREAD_FPU + 0x008)(thread); \ - lwc1 $f3, (THREAD_FPU + 0x00c)(thread); \ - lwc1 $f4, (THREAD_FPU + 0x010)(thread); \ - lwc1 $f5, (THREAD_FPU + 0x014)(thread); \ - lwc1 $f6, (THREAD_FPU + 0x018)(thread); \ - lwc1 $f7, (THREAD_FPU + 0x01c)(thread); \ - lwc1 $f8, (THREAD_FPU + 0x020)(thread); \ - lwc1 $f9, (THREAD_FPU + 0x024)(thread); \ - lwc1 $f10, (THREAD_FPU + 0x028)(thread); \ - lwc1 $f11, (THREAD_FPU + 0x02c)(thread); \ - lwc1 $f12, (THREAD_FPU + 0x030)(thread); \ - lwc1 $f13, (THREAD_FPU + 0x034)(thread); \ - lwc1 $f14, (THREAD_FPU + 0x038)(thread); \ - lwc1 $f15, (THREAD_FPU + 0x03c)(thread); \ - lwc1 $f16, (THREAD_FPU + 0x040)(thread); \ - lwc1 $f17, (THREAD_FPU + 0x044)(thread); \ - lwc1 $f18, (THREAD_FPU + 0x048)(thread); \ - lwc1 $f19, (THREAD_FPU + 0x04c)(thread); \ - lwc1 $f20, (THREAD_FPU + 0x050)(thread); \ - lwc1 $f21, (THREAD_FPU + 0x054)(thread); \ - lwc1 $f22, (THREAD_FPU + 0x058)(thread); \ - lwc1 $f23, (THREAD_FPU + 0x05c)(thread); \ - lwc1 $f24, (THREAD_FPU + 0x060)(thread); \ - lwc1 $f25, (THREAD_FPU + 0x064)(thread); \ - lwc1 $f26, (THREAD_FPU + 0x068)(thread); \ - lwc1 $f27, (THREAD_FPU + 0x06c)(thread); \ - lwc1 $f28, (THREAD_FPU + 0x070)(thread); \ - lwc1 $f29, (THREAD_FPU + 0x074)(thread); \ - lwc1 $f30, (THREAD_FPU + 0x078)(thread); \ - lwc1 $f31, (THREAD_FPU + 0x07c)(thread); \ + lwc1 $f1, (THREAD_FPU + 0x008)(thread); \ + lwc1 $f2, (THREAD_FPU + 0x010)(thread); \ + lwc1 $f3, (THREAD_FPU + 0x018)(thread); \ + lwc1 $f4, (THREAD_FPU + 0x020)(thread); \ + lwc1 $f5, (THREAD_FPU + 0x028)(thread); \ + lwc1 $f6, (THREAD_FPU + 0x030)(thread); \ + lwc1 $f7, (THREAD_FPU + 0x038)(thread); \ + lwc1 $f8, (THREAD_FPU + 0x040)(thread); \ + lwc1 $f9, (THREAD_FPU + 0x048)(thread); \ + lwc1 $f10, (THREAD_FPU + 0x050)(thread); \ + lwc1 $f11, (THREAD_FPU + 0x058)(thread); \ + lwc1 $f12, (THREAD_FPU + 0x060)(thread); \ + lwc1 $f13, (THREAD_FPU + 0x068)(thread); \ + lwc1 $f14, (THREAD_FPU + 0x070)(thread); \ + lwc1 $f15, (THREAD_FPU + 0x078)(thread); \ + lwc1 $f16, (THREAD_FPU + 0x080)(thread); \ + lwc1 $f17, (THREAD_FPU + 0x088)(thread); \ + lwc1 $f18, (THREAD_FPU + 0x090)(thread); \ + lwc1 $f19, (THREAD_FPU + 0x098)(thread); \ + lwc1 $f20, (THREAD_FPU + 0x0a0)(thread); \ + lwc1 $f21, (THREAD_FPU + 0x0a8)(thread); \ + lwc1 $f22, (THREAD_FPU + 0x0b0)(thread); \ + lwc1 $f23, (THREAD_FPU + 0x0b8)(thread); \ + lwc1 $f24, (THREAD_FPU + 0x0c0)(thread); \ + lwc1 $f25, (THREAD_FPU + 0x0c8)(thread); \ + lwc1 $f26, (THREAD_FPU + 0x0d0)(thread); \ + lwc1 $f27, (THREAD_FPU + 0x0d8)(thread); \ + lwc1 $f28, (THREAD_FPU + 0x0e0)(thread); \ + lwc1 $f29, (THREAD_FPU + 0x0e8)(thread); \ + lwc1 $f30, (THREAD_FPU + 0x0f0)(thread); \ + lwc1 $f31, (THREAD_FPU + 0x0f8)(thread); \ ctc1 tmp, fcr31 #define CPU_SAVE_NONSCRATCH(thread) \ @@ -148,4 +146,4 @@ lw fp, THREAD_REG30(thread); \ lw ra, THREAD_REG31(thread) -#endif /* !(__MIPS_ASMMACRO_H) */ +#endif /* _ASM_ASMMACRO_H */ diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h index fbd2daee70fc..63667f0c81f1 100644 --- a/include/asm-mips/atomic.h +++ b/include/asm-mips/atomic.h @@ -9,25 +9,35 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996, 1997 by Ralf Baechle - * - * $Id: atomic.h,v 1.6 1999/07/26 19:42:42 harald Exp $ + * Copyright (C) 1996, 1997, 2000 by Ralf Baechle */ #ifndef __ASM_ATOMIC_H #define __ASM_ATOMIC_H #include <linux/config.h> -#ifdef CONFIG_SMP typedef struct { volatile int counter; } atomic_t; -#else -typedef struct { int counter; } atomic_t; -#endif #ifdef __KERNEL__ #define ATOMIC_INIT(i) { (i) } +/* + * atomic_read - read atomic variable + * @v: pointer of type atomic_t + * + * Atomically reads the value of @v. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ #define atomic_read(v) ((v)->counter) + +/* + * atomic_set - set atomic variable + * @v: pointer of type atomic_t + * @i: required value + * + * Atomically sets the value of @v to @i. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ #define atomic_set(v,i) ((v)->counter = (i)) #if !defined(CONFIG_CPU_HAS_LLSC) @@ -37,8 +47,15 @@ typedef struct { int counter; } atomic_t; /* * The MIPS I implementation is only atomic with respect to * interrupts. R3000 based multiprocessor machines are rare anyway ... + * + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type atomic_t + * + * Atomically adds @i to @v. Note that the guaranteed useful range + * of an atomic_t is only 24 bits. */ -extern __inline__ void atomic_add(int i, volatile atomic_t * v) +extern __inline__ void atomic_add(int i, atomic_t * v) { int flags; @@ -48,7 +65,15 @@ extern __inline__ void atomic_add(int i, volatile atomic_t * v) restore_flags(flags); } -extern __inline__ void atomic_sub(int i, volatile atomic_t * v) +/* + * atomic_sub - subtract the atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +extern __inline__ void atomic_sub(int i, atomic_t * v) { int flags; @@ -86,21 +111,6 @@ extern __inline__ int atomic_sub_return(int i, atomic_t * v) return temp; } -extern __inline__ void atomic_clear_mask(unsigned long mask, unsigned long * v) -{ - unsigned long temp; - int flags; - - save_flags(flags); - cli(); - temp = *v; - temp &= ~mask; - *v = temp; - restore_flags(flags); - - return; -} - #else /* @@ -109,40 +119,45 @@ extern __inline__ void atomic_clear_mask(unsigned long mask, unsigned long * v) */ /* - * Make sure gcc doesn't try to be clever and move things around - * on us. We need to use _exactly_ the address the user gave us, - * not some alias that contains the same information. + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type atomic_t + * + * Atomically adds @i to @v. Note that the guaranteed useful range + * of an atomic_t is only 24 bits. */ -#define __atomic_fool_gcc(x) (*(volatile struct { int a[100]; } *)x) - -extern __inline__ void atomic_add(int i, volatile atomic_t * v) +extern __inline__ void atomic_add(int i, atomic_t * v) { unsigned long temp; __asm__ __volatile__( - "1:\tll\t%0,%1\n\t" - "addu\t%0,%2\n\t" - "sc\t%0,%1\n\t" - "beqz\t%0,1b" - :"=&r" (temp), - "=m" (__atomic_fool_gcc(v)) - :"Ir" (i), - "m" (__atomic_fool_gcc(v))); + "1: ll %0, %1 # atomic_add\n" + " addu %0, %2 \n" + " sc %0, %1 \n" + " beqz %0, 1b \n" + : "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter)); } -extern __inline__ void atomic_sub(int i, volatile atomic_t * v) +/* + * atomic_sub - subtract the atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +extern __inline__ void atomic_sub(int i, atomic_t * v) { unsigned long temp; __asm__ __volatile__( - "1:\tll\t%0,%1\n\t" - "subu\t%0,%2\n\t" - "sc\t%0,%1\n\t" - "beqz\t%0,1b" - :"=&r" (temp), - "=m" (__atomic_fool_gcc(v)) - :"Ir" (i), - "m" (__atomic_fool_gcc(v))); + "1: ll %0, %1 # atomic_sub\n" + " subu %0, %2 \n" + " sc %0, %1 \n" + " beqz %0, 1b \n" + : "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter)); } /* @@ -153,18 +168,17 @@ extern __inline__ int atomic_add_return(int i, atomic_t * v) unsigned long temp, result; __asm__ __volatile__( - ".set\tnoreorder\n" - "1:\tll\t%1,%2\n\t" - "addu\t%0,%1,%3\n\t" - "sc\t%0,%2\n\t" - "beqz\t%0,1b\n\t" - "addu\t%0,%1,%3\n\t" - ".set\treorder" - :"=&r" (result), - "=&r" (temp), - "=m" (__atomic_fool_gcc(v)) - :"Ir" (i), - "m" (__atomic_fool_gcc(v))); + ".set push # atomic_add_return\n" + ".set noreorder \n" + "1: ll %1, %2 \n" + " addu %0, %1, %3 \n" + " sc %0, %2 \n" + " beqz %0, 1b \n" + " addu %0, %1, %3 \n" + ".set pop \n" + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter) + : "memory"); return result; } @@ -174,18 +188,17 @@ extern __inline__ int atomic_sub_return(int i, atomic_t * v) unsigned long temp, result; __asm__ __volatile__( - ".set\tnoreorder\n" - "1:\tll\t%1,%2\n\t" - "subu\t%0,%1,%3\n\t" - "sc\t%0,%2\n\t" - "beqz\t%0,1b\n\t" - "subu\t%0,%1,%3\n\t" - ".set\treorder" - :"=&r" (result), - "=&r" (temp), - "=m" (__atomic_fool_gcc(v)) - :"Ir" (i), - "m" (__atomic_fool_gcc(v))); + ".set push \n" + ".set noreorder # atomic_sub_return\n" + "1: ll %1, %2 \n" + " subu %0, %1, %3 \n" + " sc %0, %2 \n" + " beqz %0, 1b \n" + " subu %0, %1, %3 \n" + ".set pop \n" + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter) + : "memory"); return result; } @@ -194,11 +207,71 @@ extern __inline__ int atomic_sub_return(int i, atomic_t * v) #define atomic_dec_return(v) atomic_sub_return(1,(v)) #define atomic_inc_return(v) atomic_add_return(1,(v)) +/* + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) + +/* + * atomic_inc_and_test - increment and test + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +#define atomic_inc_and_test(v) (atomic_inc_return(1, (v)) == 0) + +/* + * atomic_dec_and_test - decrement by 1 and test + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) +/* + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ #define atomic_inc(v) atomic_add(1,(v)) + +/* + * atomic_dec - decrement and test + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ #define atomic_dec(v) atomic_sub(1,(v)) + +/* + * atomic_add_negative - add and test if negative + * @v: pointer of type atomic_t + * @i: integer value to add + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + * + * Currently not implemented for MIPS. + */ + #endif /* defined(__KERNEL__) */ -#endif /* __ASM_MIPS_ATOMIC_H */ +#endif /* __ASM_ATOMIC_H */ diff --git a/include/asm-mips/bcache.h b/include/asm-mips/bcache.h index e3507bb042e9..e7c8071b003e 100644 --- a/include/asm-mips/bcache.h +++ b/include/asm-mips/bcache.h @@ -1,14 +1,19 @@ -/* $Id$ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 1997, 1999 by Ralf Baechle + * Copyright (c) 1997, 1999, 2000 by Ralf Baechle + * Copyright (c) 2000 by Silicon Graphics, Inc. */ #ifndef _ASM_BCACHE_H #define _ASM_BCACHE_H +#include <linux/config.h> + +/* Some R4000 / R4400 / R4600 / R5000 machines may have a non-dma-coherent, + chipset implemented caches. On machines with other CPUs the CPU does the + cache thing itself. */ struct bcache_ops { void (*bc_enable)(void); void (*bc_disable)(void); @@ -19,6 +24,39 @@ struct bcache_ops { extern void indy_sc_init(void); extern void sni_pcimt_sc_init(void); +#ifdef CONFIG_BOARD_SCACHE + extern struct bcache_ops *bcops; +extern inline void bc_enable(void) +{ + bcops->bc_enable(); +} + +extern inline void bc_disable(void) +{ + bcops->bc_disable(); +} + +extern inline void bc_wback_inv(unsigned long page, unsigned long size) +{ + bcops->bc_wback_inv(page, size); +} + +extern inline void bc_inv(unsigned long page, unsigned long size) +{ + bcops->bc_inv(page, size); +} + +#else /* !defined(CONFIG_BOARD_SCACHE) */ + +/* Not R4000 / R4400 / R4600 / R5000. */ + +#define bc_enable() do { } while (0) +#define bc_disable() do { } while (0) +#define bc_wback_inv(page, size) do { } while (0) +#define bc_inv(page, size) do { } while (0) + +#endif /* !defined(CONFIG_BOARD_SCACHE) */ + #endif /* _ASM_BCACHE_H */ diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h index 326294ab26ac..0c4e2e8df7a1 100644 --- a/include/asm-mips/bitops.h +++ b/include/asm-mips/bitops.h @@ -1,10 +1,10 @@ -/* $Id: bitops.h,v 1.7 1999/08/19 22:56:33 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 1994 - 1997, 1999 Ralf Baechle (ralf@gnu.org) + * Copyright (c) 1994 - 1997, 1999, 2000 Ralf Baechle (ralf@gnu.org) + * Copyright (c) 2000 Silicon Graphics, Inc. */ #ifndef _ASM_BITOPS_H #define _ASM_BITOPS_H @@ -19,6 +19,12 @@ #include <linux/config.h> /* + * clear_bit() doesn't provide any barrier for the compiler. + */ +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() + +/* * Only disable interrupt for kernel mode stuff to keep usermode stuff * that dares to use kernel include files alive. */ @@ -35,25 +41,6 @@ #define __bi_restore_flags(x) #endif /* __KERNEL__ */ -/* - * Note that the bit operations are defined on arrays of 32 bit sized - * elements. With respect to a future 64 bit implementation it is - * wrong to use long *. Use u32 * or int *. - */ -extern __inline__ void set_bit(int nr, void *addr); -extern __inline__ void clear_bit(int nr, void *addr); -extern __inline__ void change_bit(int nr, void *addr); -extern __inline__ int test_and_set_bit(int nr, void *addr); -extern __inline__ int test_and_clear_bit(int nr, void *addr); -extern __inline__ int test_and_change_bit(int nr, void *addr); - -extern __inline__ int test_bit(int nr, const void *addr); -#ifndef __MIPSEB__ -extern __inline__ int find_first_zero_bit (void *addr, unsigned size); -#endif -extern __inline__ int find_next_zero_bit (void * addr, int size, int offset); -extern __inline__ unsigned long ffz(unsigned long word); - #if defined(CONFIG_CPU_HAS_LLSC) #include <asm/mipsregs.h> @@ -64,92 +51,281 @@ extern __inline__ unsigned long ffz(unsigned long word); */ /* - * The following functions will only work for the R4000! + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. See __set_bit() + * if you do not require the atomic guarantees. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. */ +extern __inline__ void +set_bit(int nr, volatile void *addr) +{ + unsigned long *m = ((unsigned long *) addr) + (nr >> 5); + unsigned long temp; + + __asm__ __volatile__( + "1:\tll\t%0, %1\t\t# set_bit\n\t" + "or\t%0, %2\n\t" + "sc\t%0, %1\n\t" + "beqz\t%0, 1b" + : "=&r" (temp), "=m" (*m) + : "ir" (1UL << (nr & 0x1f)), "m" (*m)); +} -extern __inline__ void set_bit(int nr, void *addr) +/* + * __set_bit - Set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Unlike set_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ +extern __inline__ void __set_bit(int nr, volatile void * addr) { - int mask, mw; + unsigned long * m = ((unsigned long *) addr) + (nr >> 5); - addr += ((nr >> 3) & ~3); - mask = 1 << (nr & 0x1f); - do { - mw = load_linked(addr); - } while (!store_conditional(addr, mw|mask)); + *m |= 1UL << (nr & 31); } -extern __inline__ void clear_bit(int nr, void *addr) +/* + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. However, it does + * not contain a memory barrier, so if it is used for locking purposes, + * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * in order to ensure changes are visible on other processors. + */ +extern __inline__ void +clear_bit(int nr, volatile void *addr) { - int mask, mw; + unsigned long *m = ((unsigned long *) addr) + (nr >> 5); + unsigned long temp; + + __asm__ __volatile__( + "1:\tll\t%0, %1\t\t# clear_bit\n\t" + "and\t%0, %2\n\t" + "sc\t%0, %1\n\t" + "beqz\t%0, 1b\n\t" + : "=&r" (temp), "=m" (*m) + : "ir" (~(1UL << (nr & 0x1f))), "m" (*m)); +} - addr += ((nr >> 3) & ~3); - mask = 1 << (nr & 0x1f); - do { - mw = load_linked(addr); - } - while (!store_conditional(addr, mw & ~mask)); +/* + * change_bit - Toggle a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ +extern __inline__ void +change_bit(int nr, volatile void *addr) +{ + unsigned long *m = ((unsigned long *) addr) + (nr >> 5); + unsigned long temp; + + __asm__ __volatile__( + "1:\tll\t%0, %1\t\t# change_bit\n\t" + "xor\t%0, %2\n\t" + "sc\t%0, %1\n\t" + "beqz\t%0, 1b" + : "=&r" (temp), "=m" (*m) + : "ir" (1UL << (nr & 0x1f)), "m" (*m)); } -extern __inline__ void change_bit(int nr, void *addr) +/* + * __change_bit - Toggle a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Unlike change_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ +extern __inline__ void __change_bit(int nr, volatile void * addr) { - int mask, mw; + unsigned long * m = ((unsigned long *) addr) + (nr >> 5); - addr += ((nr >> 3) & ~3); - mask = 1 << (nr & 0x1f); - do { - mw = load_linked(addr); - } while (!store_conditional(addr, mw ^ mask)); + *m ^= 1UL << (nr & 31); } -extern __inline__ int test_and_set_bit(int nr, void *addr) +/* + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +extern __inline__ int +test_and_set_bit(int nr, volatile void *addr) +{ + unsigned long *m = ((unsigned long *) addr) + (nr >> 5); + unsigned long temp, res; + + __asm__ __volatile__( + ".set\tnoreorder\t\t# test_and_set_bit\n" + "1:\tll\t%0, %1\n\t" + "or\t%2, %0, %3\n\t" + "sc\t%2, %1\n\t" + "beqz\t%2, 1b\n\t" + " and\t%2, %0, %3\n\t" + ".set\treorder" + : "=&r" (temp), "=m" (*m), "=&r" (res) + : "r" (1UL << (nr & 0x1f)), "m" (*m) + : "memory"); + + return res != 0; +} + +/* + * __test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +extern __inline__ int __test_and_set_bit(int nr, volatile void * addr) { - int mask, retval, mw; + int mask, retval; + volatile int *a = addr; - addr += ((nr >> 3) & ~3); + a += nr >> 5; mask = 1 << (nr & 0x1f); - do { - mw = load_linked(addr); - retval = (mask & mw) != 0; - } while (!store_conditional(addr, mw|mask)); + retval = (mask & *a) != 0; + *a |= mask; return retval; } -extern __inline__ int test_and_clear_bit(int nr, void *addr) +/* + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +extern __inline__ int +test_and_clear_bit(int nr, volatile void *addr) { - int mask, retval, mw; + unsigned long *m = ((unsigned long *) addr) + (nr >> 5); + unsigned long temp, res; + + __asm__ __volatile__( + ".set\tnoreorder\t\t# test_and_clear_bit\n" + "1:\tll\t%0, %1\n\t" + "or\t%2, %0, %3\n\t" + "xor\t%2, %3\n\t" + "sc\t%2, %1\n\t" + "beqz\t%2, 1b\n\t" + " and\t%2, %0, %3\n\t" + ".set\treorder" + : "=&r" (temp), "=m" (*m), "=&r" (res) + : "r" (1UL << (nr & 0x1f)), "m" (*m) + : "memory"); + + return res != 0; +} + +/* + * __test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +extern __inline__ int __test_and_clear_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile int *a = addr; - addr += ((nr >> 3) & ~3); + a += nr >> 5; mask = 1 << (nr & 0x1f); - do { - mw = load_linked(addr); - retval = (mask & mw) != 0; - } - while (!store_conditional(addr, mw & ~mask)); + retval = (mask & *a) != 0; + *a &= ~mask; return retval; } -extern __inline__ int test_and_change_bit(int nr, void *addr) +/* + * test_and_change_bit - Change a bit and return its new value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +extern __inline__ int +test_and_change_bit(int nr, volatile void *addr) +{ + unsigned long *m = ((unsigned long *) addr) + (nr >> 5); + unsigned long temp, res; + + __asm__ __volatile__( + ".set\tnoreorder\t\t# test_and_change_bit\n" + "1:\tll\t%0, %1\n\t" + "xor\t%2, %0, %3\n\t" + "sc\t%2, %1\n\t" + "beqz\t%2, 1b\n\t" + " and\t%2, %0, %3\n\t" + ".set\treorder" + : "=&r" (temp), "=m" (*m), "=&r" (res) + : "r" (1UL << (nr & 0x1f)), "m" (*m) + : "memory"); + + return res != 0; +} + +/* + * __test_and_change_bit - Change a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +extern __inline__ int __test_and_change_bit(int nr, volatile void * addr) { - int mask, retval, mw; + int mask, retval; + volatile int *a = addr; - addr += ((nr >> 3) & ~3); + a += nr >> 5; mask = 1 << (nr & 0x1f); - do { - mw = load_linked(addr); - retval = (mask & mw) != 0; - } while (!store_conditional(addr, mw ^ mask)); + retval = (mask & *a) != 0; + *a ^= mask; return retval; } #else /* MIPS I */ -extern __inline__ void set_bit(int nr, void * addr) +/* + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. See __set_bit() + * if you do not require the atomic guarantees. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ +extern __inline__ void set_bit(int nr, volatile void * addr) { int mask; - int *a = addr; + volatile int *a = addr; __bi_flags; a += nr >> 5; @@ -159,10 +335,39 @@ extern __inline__ void set_bit(int nr, void * addr) __bi_restore_flags(flags); } -extern __inline__ void clear_bit(int nr, void * addr) +/* + * __set_bit - Set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Unlike set_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ +extern __inline__ void __set_bit(int nr, volatile void * addr) { int mask; - int *a = addr; + volatile int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + *a |= mask; +} + +/* + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. However, it does + * not contain a memory barrier, so if it is used for locking purposes, + * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * in order to ensure changes are visible on other processors. + */ +extern __inline__ void clear_bit(int nr, volatile void * addr) +{ + int mask; + volatile int *a = addr; __bi_flags; a += nr >> 5; @@ -172,10 +377,19 @@ extern __inline__ void clear_bit(int nr, void * addr) __bi_restore_flags(flags); } -extern __inline__ void change_bit(int nr, void * addr) +/* + * change_bit - Toggle a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ +extern __inline__ void change_bit(int nr, volatile void * addr) { int mask; - int *a = addr; + volatile int *a = addr; __bi_flags; a += nr >> 5; @@ -185,10 +399,34 @@ extern __inline__ void change_bit(int nr, void * addr) __bi_restore_flags(flags); } -extern __inline__ int test_and_set_bit(int nr, void * addr) +/* + * __change_bit - Toggle a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Unlike change_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ +extern __inline__ void __change_bit(int nr, volatile void * addr) +{ + unsigned long * m = ((unsigned long *) addr) + (nr >> 5); + + *m ^= 1UL << (nr & 31); +} + +/* + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +extern __inline__ int test_and_set_bit(int nr, volatile void * addr) { int mask, retval; - int *a = addr; + volatile int *a = addr; __bi_flags; a += nr >> 5; @@ -201,10 +439,40 @@ extern __inline__ int test_and_set_bit(int nr, void * addr) return retval; } -extern __inline__ int test_and_clear_bit(int nr, void * addr) +/* + * __test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +extern __inline__ int __test_and_set_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + retval = (mask & *a) != 0; + *a |= mask; + + return retval; +} + +/* + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +extern __inline__ int test_and_clear_bit(int nr, volatile void * addr) { int mask, retval; - int *a = addr; + volatile int *a = addr; __bi_flags; a += nr >> 5; @@ -217,10 +485,40 @@ extern __inline__ int test_and_clear_bit(int nr, void * addr) return retval; } -extern __inline__ int test_and_change_bit(int nr, void * addr) +/* + * __test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +extern __inline__ int __test_and_clear_bit(int nr, volatile void * addr) { int mask, retval; - int *a = addr; + volatile int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + retval = (mask & *a) != 0; + *a &= ~mask; + + return retval; +} + +/* + * test_and_change_bit - Change a bit and return its new value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +extern __inline__ int test_and_change_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile int *a = addr; __bi_flags; a += nr >> 5; @@ -233,14 +531,41 @@ extern __inline__ int test_and_change_bit(int nr, void * addr) return retval; } +/* + * __test_and_change_bit - Change a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +extern __inline__ int __test_and_change_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile int *a = addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + retval = (mask & *a) != 0; + *a ^= mask; + + return retval; +} + #undef __bi_flags -#undef __bi_cli() -#undef __bi_save_flags(x) -#undef __bi_restore_flags(x) +#undef __bi_cli +#undef __bi_save_flags +#undef __bi_restore_flags #endif /* MIPS I */ -extern __inline__ int test_bit(int nr, const void *addr) +/* + * test_bit - Determine whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +extern __inline__ int test_bit(int nr, volatile void *addr) { return ((1UL << (nr & 31)) & (((const unsigned int *) addr)[nr >> 5])) != 0; } @@ -249,6 +574,14 @@ extern __inline__ int test_bit(int nr, const void *addr) /* Little endian versions. */ +/* + * find_first_zero_bit - find the first zero bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first zero bit, not the number of the byte + * containing a bit. + */ extern __inline__ int find_first_zero_bit (void *addr, unsigned size) { unsigned long dummy; @@ -285,18 +618,20 @@ extern __inline__ int find_first_zero_bit (void *addr, unsigned size) ".set\tat\n\t" ".set\treorder\n" "2:" - : "=r" (res), - "=r" (dummy), - "=r" (addr) - : "0" ((signed int) 0), - "1" ((unsigned int) 0xffffffff), - "2" (addr), - "r" (size) + : "=r" (res), "=r" (dummy), "=r" (addr) + : "0" ((signed int) 0), "1" ((unsigned int) 0xffffffff), + "2" (addr), "r" (size) : "$1"); return res; } +/* + * find_next_zero_bit - find the first zero bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ extern __inline__ int find_next_zero_bit (void * addr, int size, int offset) { unsigned int *p = ((unsigned int *) addr) + (offset >> 5); @@ -320,11 +655,8 @@ extern __inline__ int find_next_zero_bit (void * addr, int size, int offset) ".set\tat\n\t" ".set\treorder\n" "1:" - : "=r" (set), - "=r" (dummy) - : "0" (0), - "1" (1 << bit), - "r" (*p) + : "=r" (set), "=r" (dummy) + : "0" (0), "1" (1 << bit), "r" (*p) : "$1"); if (set < (32 - bit)) return set + offset; @@ -341,8 +673,10 @@ extern __inline__ int find_next_zero_bit (void * addr, int size, int offset) #endif /* !(__MIPSEB__) */ /* - * ffz = Find First Zero in word. Undefined if no zero exists, - * so code should check against ~0UL first.. + * ffz - find first zero in word. + * @word: The word to search + * + * Undefined if no zero exists, so code should check against ~0UL first. */ extern __inline__ unsigned long ffz(unsigned long word) { @@ -370,8 +704,11 @@ extern __inline__ unsigned long ffz(unsigned long word) #ifdef __KERNEL__ -/* - * ffs: find first bit set. This is defined the same way as +/** + * ffs - find first bit set + * @x: the word to search + * + * This is defined the same way as * the libc and compiler builtin ffs routines, therefore * differs in spirit from the above ffz (man ffs). */ @@ -379,8 +716,10 @@ extern __inline__ unsigned long ffz(unsigned long word) #define ffs(x) generic_ffs(x) /* - * hweightN: returns the hamming weight (i.e. the number - * of bits set) of a N-bit word + * hweightN - returns the hamming weight of a N-bit word + * @x: the word to weigh + * + * The Hamming Weight of a number is the total number of bits set in it. */ #define hweight32(x) generic_hweight32(x) @@ -390,14 +729,12 @@ extern __inline__ unsigned long ffz(unsigned long word) #endif /* __KERNEL__ */ #ifdef __MIPSEB__ -/* For now I steal the Sparc C versions, no need for speed, just need to - * get it working. - */ -/* find_next_zero_bit() finds the first zero bit in a bit string of length - * 'size' bits, starting the search at bit 'offset'. This is largely based - * on Linus's ALPHA routines, which are pretty portable BTW. +/* + * find_next_zero_bit - find the first zero bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search */ - extern __inline__ int find_next_zero_bit(void *addr, int size, int offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 5); @@ -438,6 +775,18 @@ found_middle: * holds on the Sparc as it does for the ALPHA. */ +#if 0 /* Fool kernel-doc since it doesn't do macros yet */ +/* + * find_first_zero_bit - find the first zero bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first zero bit, not the number of the byte + * containing a bit. + */ +extern int find_first_zero_bit (void *addr, unsigned size); +#endif + #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) @@ -451,7 +800,6 @@ extern __inline__ int ext2_set_bit(int nr,void * addr) int mask, retval, flags; unsigned char *ADDR = (unsigned char *) addr; - ADDR += nr >> 3; mask = 1 << (nr & 0x07); save_and_cli(flags); retval = (mask & *ADDR) != 0; diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h index f1c30ece0f25..128de8dc893c 100644 --- a/include/asm-mips/bootinfo.h +++ b/include/asm-mips/bootinfo.h @@ -18,14 +18,23 @@ #define MACH_GROUP_ARC 3 /* Wreckstation Tyne, rPC44, possibly other */ #define MACH_GROUP_SNI_RM 4 /* Siemens Nixdorf RM series */ #define MACH_GROUP_ACN 5 -#define MACH_GROUP_SGI 6 /* Silicon Graphics workstations and servers */ +#define MACH_GROUP_SGI 6 /* Silicon Graphics */ #define MACH_GROUP_COBALT 7 /* Cobalt servers */ -#define MACH_GROUP_NEC_DDB 8 /* NEC DDB */ -#define MACH_GROUP_BAGET 9 /* Baget */ -#define MACH_GROUP_ORION 10 /* CoSine Orion */ - -#define GROUP_NAMES { "unknown", "Jazz", "Digital", "ARC", \ - "SNI", "ACN", "SGI", "Cobalt", "NEC DDB", "Baget", "Orion" } +#define MACH_GROUP_NEC_DDB 8 /* NEC DDB */ +#define MACH_GROUP_BAGET 9 /* Baget */ +#define MACH_GROUP_COSINE 10 /* CoSine Orion */ +#define MACH_GROUP_GALILEO 11 /* Galileo Eval Boards */ +#define MACH_GROUP_MOMENCO 12 /* Momentum Boards */ +#define MACH_GROUP_ITE 13 /* ITE Semi Eval Boards */ +#define MACH_GROUP_PHILIPS 14 +#define MACH_GROUP_GLOBESPAN 15 /* Globespan PVR Referrence Board */ +#define MACH_GROUP_SIBYTE 16 /* Sibyte Eval Boards */ +#define MACH_GROUP_TOSHIBA 17 /* Toshiba Reference Systems TSBREF */ +#define MACH_GROUP_ALCHEMY 18 /* Alchemy Semi Eval Boards*/ + +#define GROUP_NAMES { "unknown", "Jazz", "Digital", "ARC", "SNI", "ACN", \ + "SGI", "Cobalt", "NEC DDB", "Baget", "Cosine", "Galileo", "Momentum", \ + "ITE", "Philips", "Globepspan", "SiByte", "Toshiba", "Alchemy" } /* * Valid machtype values for group unknown (low order halfword of mips_machtype) @@ -87,9 +96,11 @@ /* * Valid machtype for group SGI */ -#define MACH_SGI_INDY 0 /* R4?K and R5K Indy workstaions */ +#define MACH_SGI_INDY 0 /* R4?K and R5K Indy workstations */ +#define MACH_SGI_CHALLENGE_S 1 /* The Challenge S server */ +#define MACH_SGI_INDIGO2 2 /* The Indigo2 system */ -#define GROUP_SGI_NAMES { "Indy" } +#define GROUP_SGI_NAMES { "Indy", "Challenge S", "Indigo2" } /* * Valid machtype for group COBALT @@ -103,8 +114,9 @@ */ #define MACH_NEC_DDB5074 0 /* NEC DDB Vrc-5074 */ #define MACH_NEC_DDB5476 1 /* NEC DDB Vrc-5476 */ +#define MACH_NEC_DDB5477 2 /* NEC DDB Vrc-5477 */ -#define GROUP_NEC_DDB_NAMES { "Vrc-5074", "Vrc-5476"} +#define GROUP_NEC_DDB_NAMES { "Vrc-5074", "Vrc-5476", "Vrc-5477"} /* * Valid machtype for group BAGET @@ -115,6 +127,74 @@ #define GROUP_BAGET_NAMES { "BT23-201", "BT23-202" } /* + * Cosine boards. + */ +#define MACH_COSINE_ORION 0 + +#define GROUP_COSINE_NAMES { "Orion" } + +/* + * Valid machtype for group GALILEO + */ +#define MACH_EV96100 0 /* EV96100 */ +#define MACH_EV64120A 1 /* EV64120A */ + +#define GROUP_GALILEO_NAMES { "EV96100" , "EV64120A" } + +/* + * Valid machtype for group MOMENCO + */ +#define MACH_MOMENCO_OCELOT 0 + +#define GROUP_MOMENCO_NAMES { "Ocelot" } + + +/* + * Valid machtype for group ITE + */ +#define MACH_QED_4N_S01B 0 /* ITE8172 based eval board */ + +#define GROUP_ITE_NAMES { "QED-4N-S01B" } /* the actual board name */ + +/* + * Valid machtype for group Globespan + */ +#define MACH_IVR 0 /* IVR eval board */ + +#define GROUP_GLOBESPAN_NAMES { "IVR" } /* the actual board name */ + +/* + * Valid machtype for group PHILIPS + */ +#define MACH_PHILIPS_NINO 0 /* Nino */ +#define MACH_PHILIPS_VELO 1 /* Velo */ + +#define GROUP_PHILIPS_NAMES { "Nino" , "Velo" } + +/* + * Valid machtype for group SIBYTE + */ +#define MACH_SWARM 0 + +#define GROUP_SIBYTE_NAMES {"SWARM" } + +/* + * Valid machtypes for group Toshiba + */ +#define MACH_PALLAS 0 +#define MACH_TOPAS 1 +#define MACH_JMR 2 + +#define GROUP_TOSHIBA_NAMES { "Pallas", "TopasCE", "JMR" } + +/* + * Valid machtype for group Alchemy + */ +#define MACH_PB1000 0 /* Au1000-based eval board */ + +#define GROUP_ALCHEMY_NAMES { "PB1000" } /* the actual board name */ + +/* * Valid cputype values */ #define CPU_UNKNOWN 0 @@ -145,17 +225,36 @@ #define CPU_R5000A 25 #define CPU_R4640 26 #define CPU_NEVADA 27 /* RM5230, RM5260 */ -#define CPU_LAST 27 +#define CPU_RM7000 28 +#define CPU_R5432 29 +#define CPU_4KC 30 +#define CPU_5KC 31 +#define CPU_R4310 32 +#define CPU_SB1 33 +#define CPU_TX3912 34 +#define CPU_TX3922 35 +#define CPU_TX3927 36 +#define CPU_AU1000 37 +#define CPU_4KEC 37 +#define CPU_4KSC 38 +#define CPU_LAST 39 #define CPU_NAMES { "unknown", "R2000", "R3000", "R3000A", "R3041", "R3051", \ "R3052", "R3081", "R3081E", "R4000PC", "R4000SC", "R4000MC", \ "R4200", "R4400PC", "R4400SC", "R4400MC", "R4600", "R6000", \ "R6000A", "R8000", "R10000", "R4300", "R4650", "R4700", "R5000", \ - "R5000A", "R4640", "Nevada" } + "R5000A", "R4640", "Nevada", "RM7000", "R5432", "MIPS 4Kc", \ + "MIPS 5Kc", "R4310", "SiByte SB1", "TX3912", "TX3922", "TX3927", \ + "Au1000", "MIPS 4KEc", "MIPS 4KSc" } -#define CL_SIZE (80) +#define COMMAND_LINE_SIZE 256 -#ifndef _LANGUAGE_ASSEMBLY +#define BOOT_MEM_MAP_MAX 32 +#define BOOT_MEM_RAM 1 +#define BOOT_MEM_ROM_DATA 2 +#define BOOT_MEM_RESERVED 3 + +#ifndef __ASSEMBLY__ /* * Some machine parameters passed by the bootloaders. @@ -183,12 +282,29 @@ typedef struct mips_arc_DisplayInfo { /* video adapter information */ * values in setup.c (or whereever suitable) so they are in * .data section */ -extern unsigned long mips_memory_upper; -extern unsigned long mips_cputype; +extern struct mips_cpu mips_cpu; extern unsigned long mips_machtype; extern unsigned long mips_machgroup; extern unsigned long mips_tlb_entries; -#endif /* _LANGUAGE_ASSEMBLY */ +/* + * A memory map that's built upon what was determined + * or specified on the command line. + */ +struct boot_mem_map { + int nr_map; + struct { + unsigned long addr; /* start of memory segment */ + unsigned long size; /* size of memory segment */ + long type; /* type of memory segment */ + } map[BOOT_MEM_MAP_MAX]; +}; + +extern struct boot_mem_map boot_mem_map; + +extern void add_memory_region(unsigned long start, unsigned long size, + long type); + +#endif /* !__ASSEMBLY__ */ -#endif /* __ASM_MIPS_BOOTINFO_H */ +#endif /* _ASM_BOOTINFO_H */ diff --git a/include/asm-mips/bugs.h b/include/asm-mips/bugs.h index 7a7871dd3c57..17b94e2693cc 100644 --- a/include/asm-mips/bugs.h +++ b/include/asm-mips/bugs.h @@ -1,9 +1,9 @@ -/* $Id: bugs.h,v 1.4 1999/08/18 23:37:49 ralf Exp $ - * +/* * Copyright (C) 1995 Waldorf Electronics * Copyright (C) 1997, 1999 Ralf Baechle */ #include <asm/bootinfo.h> +#include <asm/cpu.h> /* * This is included by init/main.c to check for architecture-dependent bugs. @@ -16,7 +16,7 @@ static inline void check_wait(void) { printk("Checking for 'wait' instruction... "); - switch(mips_cputype) { + switch(mips_cpu.cputype) { case CPU_R3081: case CPU_R3081E: cpu_wait = r3081_wait; @@ -30,6 +30,7 @@ static inline void check_wait(void) case CPU_R4700: case CPU_R5000: case CPU_NEVADA: + case CPU_RM7000: cpu_wait = r4k_wait; printk(" available.\n"); break; diff --git a/include/asm-mips/cache.h b/include/asm-mips/cache.h index a6c80d31ee3e..28f08756ed0e 100644 --- a/include/asm-mips/cache.h +++ b/include/asm-mips/cache.h @@ -1,10 +1,9 @@ -/* $Id: cache.h,v 1.4 2000/02/04 07:40:53 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1997, 1998, 1999 Ralf Baechle + * Copyright (C) 1997, 98, 99, 2000 Ralf Baechle * Copyright (C) 1999 Silicon Graphics, Inc. */ #ifndef _ASM_CACHE_H @@ -12,6 +11,23 @@ #include <linux/config.h> +#ifndef _LANGUAGE_ASSEMBLY +/* + * Descriptor for a cache + */ +struct cache_desc { + int linesz; + int sets; + int ways; + int flags; /* Details like write thru/back, coherent, etc. */ +}; +#endif + +/* + * Flag definitions + */ +#define MIPS_CACHE_NOT_PRESENT 0x00000001 + #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_R6000) #define L1_CACHE_BYTES 16 #else diff --git a/include/asm-mips/checksum.h b/include/asm-mips/checksum.h index 25e303e8cb02..a9b5d7e5471a 100644 --- a/include/asm-mips/checksum.h +++ b/include/asm-mips/checksum.h @@ -1,10 +1,9 @@ -/* $Id: checksum.h,v 1.8 2000/02/18 00:24:48 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle + * Copyright (C) 1995, 1996, 1997, 1998, 2001 by Ralf Baechle */ #ifndef _ASM_CHECKSUM_H #define _ASM_CHECKSUM_H @@ -23,7 +22,7 @@ * * it's best to have buff aligned on a 32-bit boundary */ -unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum); +unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum); /* * this is a new version of the above that records errors it finds in *errp, @@ -42,9 +41,9 @@ unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len, * Copy and checksum to user */ #define HAVE_CSUM_COPY_USER -extern inline unsigned int -csum_and_copy_to_user (const char *src, char *dst, - int len, int sum, int *err_ptr) +extern inline unsigned int csum_and_copy_to_user (const char *src, char *dst, + int len, int sum, + int *err_ptr) { sum = csum_partial(src, len, sum); @@ -63,22 +62,23 @@ csum_and_copy_to_user (const char *src, char *dst, * this is obsolete and will go away. */ #define csum_partial_copy_fromuser csum_partial_copy -unsigned int csum_partial_copy(const char *src, char *dst, int len, unsigned int sum); - +unsigned int csum_partial_copy(const char *src, char *dst, int len, + unsigned int sum); + /* * Fold a partial checksum without adding pseudo headers */ static inline unsigned short int csum_fold(unsigned int sum) { - __asm__(" - .set noat - sll $1,%0,16 - addu %0,$1 - sltu $1,%0,$1 - srl %0,%0,16 - addu %0,$1 - xori %0,0xffff - .set at" + __asm__( + ".set\tnoat\t\t\t# csum_fold\n\t" + "sll\t$1,%0,16\n\t" + "addu\t%0,$1\n\t" + "sltu\t$1,%0,$1\n\t" + "srl\t%0,%0,16\n\t" + "addu\t%0,$1\n\t" + "xori\t%0,0xffff\n\t" + ".set\tat" : "=r" (sum) : "0" (sum) : "$1"); @@ -93,7 +93,7 @@ static inline unsigned short int csum_fold(unsigned int sum) * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by * Arnt Gulbrandsen. */ -static inline unsigned short ip_fast_csum(unsigned char * iph, +static inline unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl) { unsigned int sum; @@ -102,37 +102,36 @@ static inline unsigned short ip_fast_csum(unsigned char * iph, /* * This is for 32-bit MIPS processors. */ - __asm__ __volatile__(" - .set noreorder - .set noat - lw %0,(%1) - subu %2,4 - #blez %2,2f - sll %2,2 # delay slot + __asm__ __volatile__( + ".set\tnoreorder\t\t\t# ip_fast_csum\n\t" + ".set\tnoat\n\t" + "lw\t%0, (%1)\n\t" + "subu\t%2, 4\n\t" + "#blez\t%2, 2f\n\t" + " sll\t%2, 2\n\t" + "lw\t%3, 4(%1)\n\t" + "addu\t%2, %1\n\t" + "addu\t%0, %3\n\t" + "sltu\t$1, %0, %3\n\t" + "lw\t%3, 8(%1)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %3\n\t" + "sltu\t$1, %0, %3\n\t" + "lw\t%3, 12(%1)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %3\n\t" + "sltu\t$1, %0, %3\n\t" + "addu\t%0, $1\n" - lw %3,4(%1) - addu %2,%1 # delay slot - addu %0,%3 - sltu $1,%0,%3 - lw %3,8(%1) - addu %0,$1 - addu %0,%3 - sltu $1,%0,%3 - lw %3,12(%1) - addu %0,$1 - addu %0,%3 - sltu $1,%0,%3 - addu %0,$1 + "1:\tlw\t%3, 16(%1)\n\t" + "addiu\t%1, 4\n\t" + "addu\t%0, %3\n\t" + "sltu\t$1, %0, %3\n\t" + "bne\t%2, %1, 1b\n\t" + " addu\t%0, $1\n" -1: lw %3,16(%1) - addiu %1,4 - addu %0,%3 - sltu $1,%0,%3 - bne %2,%1,1b - addu %0,$1 # delay slot - -2: .set at - .set reorder" + "2:\t.set\tat\n\t" + ".set\treorder" : "=&r" (sum), "=&r" (iph), "=&r" (ihl), "=&r" (dummy) : "1" (iph), "2" (ihl) : "$1"); @@ -150,28 +149,28 @@ static inline unsigned long csum_tcpudp_nofold(unsigned long saddr, unsigned short proto, unsigned int sum) { - __asm__(" - .set noat - addu %0,%2 - sltu $1,%0,%2 - addu %0,$1 + __asm__( + ".set\tnoat\t\t\t# csum_tcpudp_nofold\n\t" + "addu\t%0, %2\n\t" + "sltu\t$1, %0, %2\n\t" + "addu\t%0, $1\n\t" - addu %0,%3 - sltu $1,%0,%3 - addu %0,$1 + "addu\t%0, %3\n\t" + "sltu\t$1, %0, %3\n\t" + "addu\t%0, $1\n\t" - addu %0,%4 - sltu $1,%0,%4 - addu %0,$1 - .set at" + "addu\t%0, %4\n\t" + "sltu\t$1, %0, %4\n\t" + "addu\t%0, $1\n\t" + ".set\tat" : "=r" (sum) : "0" (daddr), "r"(saddr), #ifdef __MIPSEL__ - "r" ((ntohs(len)<<16)+proto*256), + "r" ((ntohs(len)<<16)+proto*256), #else - "r" (((proto)<<16)+len), + "r" (((proto)<<16)+len), #endif - "r"(sum) + "r" (sum) : "$1"); return sum; @@ -187,7 +186,7 @@ static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, unsigned short proto, unsigned int sum) { - return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); + return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); } /* @@ -206,64 +205,60 @@ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, unsigned short proto, unsigned int sum) { - __asm__(" - .set noreorder - .set noat - addu %0,%5 # proto (long in network byte order) - sltu $1,%0,%5 - addu %0,$1 + __asm__( + ".set\tnoreorder\t\t\t# csum_ipv6_magic\n\t" + ".set\tnoat\n\t" + "addu\t%0, %5\t\t\t# proto (long in network byte order)\n\t" + "sltu\t$1, %0, %5\n\t" + "addu\t%0, $1\n\t" - addu %0,%6 # csum - sltu $1,%0,%6 - lw %1,0(%2) # four words source address - addu %0,$1 - addu %0,%1 - sltu $1,%0,$1 + "addu\t%0, %6\t\t\t# csum\n\t" + "sltu\t$1, %0, %6\n\t" + "lw\t%1, 0(%2)\t\t\t# four words source address\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" - lw %1,4(%2) - addu %0,$1 - addu %0,%1 - sltu $1,%0,$1 + "lw\t%1, 4(%2)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" - lw %1,8(%2) - addu %0,$1 - addu %0,%1 - sltu $1,%0,$1 + "lw\t%1, 8(%2)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" - lw %1,12(%2) - addu %0,$1 - addu %0,%1 - sltu $1,%0,$1 + "lw\t%1, 12(%2)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" - lw %1,0(%3) - addu %0,$1 - addu %0,%1 - sltu $1,%0,$1 + "lw\t%1, 0(%3)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" - lw %1,4(%3) - addu %0,$1 - addu %0,%1 - sltu $1,%0,$1 + "lw\t%1, 4(%3)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" - lw %1,8(%3) - addu %0,$1 - addu %0,%1 - sltu $1,%0,$1 + "lw\t%1, 8(%3)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" - lw %1,12(%3) - addu %0,$1 - addu %0,%1 - sltu $1,%0,$1 - .set noat - .set noreorder" - : "=r" (sum), - "=r" (proto) - : "r" (saddr), - "r" (daddr), - "0" (htonl(len)), - "1" (htonl(proto)), - "r"(sum) - : "$1"); + "lw\t%1, 12(%3)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" + ".set\tnoat\n\t" + ".set\tnoreorder" + : "=r" (sum), "=r" (proto) + : "r" (saddr), "r" (daddr), + "0" (htonl(len)), "1" (htonl(proto)), "r" (sum) + : "$1"); return csum_fold(sum); } diff --git a/include/asm-mips/cpu.h b/include/asm-mips/cpu.h index 4d42be6f1334..73c4a711dddd 100644 --- a/include/asm-mips/cpu.h +++ b/include/asm-mips/cpu.h @@ -1,40 +1,132 @@ -/* $Id: cpu.h,v 1.1 1996/06/23 09:38:33 dm Exp $ +/* * cpu.h: Values of the PRId register used to match up * various MIPS cpu types. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) */ -#ifndef _MIPS_CPU_H -#define _MIPS_CPU_H +#ifndef _ASM_CPU_H +#define _ASM_CPU_H + +#include <asm/cache.h> +/* Assigned Company values for bits 23:16 of the PRId Register + (CP0 register 15, select 0). As of the MIPS32 and MIPS64 specs from + MTI, the PRId register is defined in this (backwards compatible) + way: + + +----------------+----------------+----------------+----------------+ + | Company Options| Company ID | Processor ID | Revision | + +----------------+----------------+----------------+----------------+ + 31 24 23 16 15 8 7 + + I don't have docs for all the previous processors, but my impression is + that bits 16-23 have been 0 for all MIPS processors before the MIPS32/64 + spec. +*/ + +#define PRID_COMP_LEGACY 0x000000 +#define PRID_COMP_MIPS 0x010000 +#define PRID_COMP_ALCHEMY 0x030000 +/* + * Don't know who should be here...QED and Sandcraft, maybe? + */ +#define PRID_COMP_SIBYTE 0x040000 /* * Assigned values for the product ID register. In order to detect a * certain CPU type exactly eventually additional registers may need to - * be examined. - */ -#define PRID_IMP_R2000 0x0100 -#define PRID_IMP_R3000 0x0200 -#define PRID_IMP_R6000 0x0300 -#define PRID_IMP_R4000 0x0400 -#define PRID_IMP_R6000A 0x0600 -#define PRID_IMP_R10000 0x0900 -#define PRID_IMP_R4300 0x0b00 -#define PRID_IMP_R8000 0x1000 -#define PRID_IMP_R4600 0x2000 -#define PRID_IMP_R4700 0x2100 -#define PRID_IMP_R4640 0x2200 -#define PRID_IMP_R4650 0x2200 /* Same as R4640 */ -#define PRID_IMP_R5000 0x2300 -#define PRID_IMP_SONIC 0x2400 -#define PRID_IMP_MAGIC 0x2500 -#define PRID_IMP_RM7000 0x2700 -#define PRID_IMP_NEVADA 0x2800 /* RM5260 ??? */ - -#define PRID_IMP_UNKNOWN 0xff00 - -#define PRID_REV_R4400 0x0040 -#define PRID_REV_R3000A 0x0030 -#define PRID_REV_R3000 0x0020 -#define PRID_REV_R2000A 0x0010 - -#endif /* !(_MIPS_CPU_H) */ + * be examined. These are valid when 23:16 == PRID_COMP_LEGACY + */ +#define PRID_IMP_R2000 0x0100 +#define PRID_IMP_AU1000 0x0100 +#define PRID_IMP_R3000 0x0200 /* Same as R2000A */ +#define PRID_IMP_R6000 0x0300 /* Same as R3000A */ +#define PRID_IMP_R4000 0x0400 +#define PRID_IMP_R6000A 0x0600 +#define PRID_IMP_R10000 0x0900 +#define PRID_IMP_R4300 0x0b00 +#define PRID_IMP_R12000 0x0e00 +#define PRID_IMP_R8000 0x1000 +#define PRID_IMP_R4600 0x2000 +#define PRID_IMP_R4700 0x2100 +#define PRID_IMP_TX39 0x2200 +#define PRID_IMP_R4640 0x2200 +#define PRID_IMP_R4650 0x2200 /* Same as R4640 */ +#define PRID_IMP_R5000 0x2300 +#define PRID_IMP_R5432 0x5400 +#define PRID_IMP_SONIC 0x2400 +#define PRID_IMP_MAGIC 0x2500 +#define PRID_IMP_RM7000 0x2700 +#define PRID_IMP_NEVADA 0x2800 /* RM5260 ??? */ +#define PRID_IMP_4KC 0x8000 +#define PRID_IMP_5KC 0x8100 +#define PRID_IMP_4KEC 0x8400 +#define PRID_IMP_4KSC 0x8600 + + +#define PRID_IMP_UNKNOWN 0xff00 + +/* + * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE + */ + +#define PRID_IMP_SB1 0x0100 + +/* + * Definitions for 7:0 on legacy processors + */ + + +#define PRID_REV_R4400 0x0040 +#define PRID_REV_R3000A 0x0030 +#define PRID_REV_R3000 0x0020 +#define PRID_REV_R2000A 0x0010 +#define PRID_REV_TX3912 0x0010 +#define PRID_REV_TX3922 0x0030 +#define PRID_REV_TX3927 0x0040 + +#ifndef _LANGUAGE_ASSEMBLY +/* + * Capability and feature descriptor structure for MIPS CPU + */ +struct mips_cpu { + unsigned int processor_id; + unsigned int cputype; /* Old "mips_cputype" code */ + int isa_level; + int options; + int tlbsize; + struct cache_desc icache; /* Primary I-cache */ + struct cache_desc dcache; /* Primary D or combined I/D cache */ + struct cache_desc scache; /* Secondary cache */ + struct cache_desc tcache; /* Tertiary/split secondary cache */ +}; + +#endif + +/* + * ISA Level encodings + */ +#define MIPS_CPU_ISA_I 0x00000001 +#define MIPS_CPU_ISA_II 0x00000002 +#define MIPS_CPU_ISA_III 0x00000003 +#define MIPS_CPU_ISA_IV 0x00000004 +#define MIPS_CPU_ISA_V 0x00000005 +#define MIPS_CPU_ISA_M32 0x00000020 +#define MIPS_CPU_ISA_M64 0x00000040 + +/* + * CPU Option encodings + */ +#define MIPS_CPU_TLB 0x00000001 /* CPU has TLB */ +/* Leave a spare bit for variant MMU types... */ +#define MIPS_CPU_4KEX 0x00000004 /* "R4K" exception model */ +#define MIPS_CPU_4KTLB 0x00000008 /* "R4K" TLB handler */ +#define MIPS_CPU_FPU 0x00000010 /* CPU has FPU */ +#define MIPS_CPU_32FPR 0x00000020 /* 32 dbl. prec. FP registers */ +#define MIPS_CPU_COUNTER 0x00000040 /* Cycle count/compare */ +#define MIPS_CPU_WATCH 0x00000080 /* watchpoint registers */ +#define MIPS_CPU_MIPS16 0x00000100 /* code compression */ +#define MIPS_CPU_DIVEC 0x00000200 /* dedicated interrupt vector */ +#define MIPS_CPU_VCE 0x00000400 /* virt. coherence conflict possible */ +#define MIPS_CPU_CACHE_CDEX 0x00000800 /* Create_Dirty_Exclusive CACHE op */ + +#endif /* _ASM_CPU_H */ diff --git a/include/asm-mips/current.h b/include/asm-mips/current.h index 3015ce4bd256..2c776757e74a 100644 --- a/include/asm-mips/current.h +++ b/include/asm-mips/current.h @@ -1,5 +1,4 @@ -/* $Id: current.h,v 1.5 1999/07/26 19:42:43 harald Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -16,21 +15,5 @@ register struct task_struct *current asm("$28"); #endif /* _LANGUAGE_C */ -#ifdef _LANGUAGE_ASSEMBLY - -/* - * Special variant for use by exception handlers when the stack pointer - * is not loaded. - */ -#define _GET_CURRENT(reg) \ - lui reg, %hi(kernelsp); \ - .set push; \ - .set reorder; \ - lw reg, %lo(kernelsp)(reg); \ - .set pop; \ - ori reg, 8191; \ - xori reg, 8191 - -#endif #endif /* _ASM_CURRENT_H */ diff --git a/include/asm-mips/delay.h b/include/asm-mips/delay.h index 7628fe4a8cdb..50024e3481c1 100644 --- a/include/asm-mips/delay.h +++ b/include/asm-mips/delay.h @@ -1,17 +1,18 @@ -/* $Id: delay.h,v 1.2 1999/01/04 16:09:20 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1994 by Waldorf Electronics - * Copyright (C) 1995 - 1998 by Ralf Baechle + * Copyright (C) 1995 - 1998, 2001 by Ralf Baechle */ #ifndef _ASM_DELAY_H #define _ASM_DELAY_H #include <linux/config.h> +extern unsigned long loops_per_jiffy; + extern __inline__ void __delay(unsigned long loops) { @@ -34,21 +35,21 @@ __delay(unsigned long loops) * first constant multiplications gets optimized away if the delay is * a constant) */ -extern __inline__ void __udelay(unsigned long usecs, unsigned long lps) +extern __inline__ void __udelay(unsigned long usecs, unsigned long lpj) { unsigned long lo; - usecs *= 0x000010c6; /* 2**32 / 1000000 */ + usecs *= 0x00068db8; /* 2**32 / (1000000 / HZ) */ __asm__("multu\t%2,%3" :"=h" (usecs), "=l" (lo) - :"r" (usecs),"r" (lps)); + :"r" (usecs),"r" (lpj)); __delay(usecs); } #ifdef CONFIG_SMP #define __udelay_val cpu_data[smp_processor_id()].udelay_val #else -#define __udelay_val loops_per_sec +#define __udelay_val loops_per_jiffy #endif #define udelay(usecs) __udelay((usecs),__udelay_val) diff --git a/include/asm-mips/div64.h b/include/asm-mips/div64.h index 58a7b437e800..9ff7bd640799 100644 --- a/include/asm-mips/div64.h +++ b/include/asm-mips/div64.h @@ -1,4 +1,7 @@ -/* $Id: div64.h,v 1.1 2000/01/28 23:18:43 ralf Exp $ +/* + * include/asm-mips/div64.h + * + * Copyright (C) 2000 Maciej W. Rozycki * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -7,14 +10,104 @@ #ifndef _ASM_DIV64_H #define _ASM_DIV64_H +#include <asm/sgidefs.h> + /* - * Hey, we're already 64-bit, no - * need to play games.. + * No traps on overflows for any of these... */ -#define do_div(n,base) ({ \ - int __res; \ - __res = ((unsigned long) n) % (unsigned) base; \ - n = ((unsigned long) n) / (unsigned) base; \ - __res; }) + +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + +#define do_div64_32(res, high, low, base) ({ \ + unsigned long __quot, __mod; \ + unsigned long __cf, __tmp, __i; \ + \ + __asm__(".set push\n\t" \ + ".set noat\n\t" \ + ".set noreorder\n\t" \ + "b 1f\n\t" \ + " li %4,0x21\n" \ + "0:\n\t" \ + "sll $1,%0,0x1\n\t" \ + "srl %3,%0,0x1f\n\t" \ + "or %0,$1,$2\n\t" \ + "sll %1,%1,0x1\n\t" \ + "sll %2,%2,0x1\n" \ + "1:\n\t" \ + "bnez %3,2f\n\t" \ + "sltu $2,%0,%z5\n\t" \ + "bnez $2,3f\n\t" \ + "2:\n\t" \ + " addiu %4,%4,-1\n\t" \ + "subu %0,%0,%z5\n\t" \ + "addiu %2,%2,1\n" \ + "3:\n\t" \ + "bnez %4,0b\n\t" \ + " srl $2,%1,0x1f\n\t" \ + ".set pop" \ + : "=&r" (__mod), "=&r" (__tmp), "=&r" (__quot), "=&r" (__cf), \ + "=&r" (__i) \ + : "Jr" (base), "0" (high), "1" (low), "2" (0), "3" (0) \ + /* Aarrgh! Ran out of gcc's limit on constraints... */ \ + : "$1", "$2"); \ + \ + (res) = __quot; \ + __mod; }) + +#define do_div(n, base) ({ \ + unsigned long long __quot; \ + unsigned long __upper, __low, __high, __mod; \ + \ + __quot = (n); \ + __high = __quot >> 32; \ + __low = __quot; \ + __upper = __high; \ + \ + if (__high) \ + __asm__("divu $0,%z2,%z3" \ + : "=h" (__upper), "=l" (__high) \ + : "Jr" (__high), "Jr" (base)); \ + \ + __mod = do_div64_32(__low, __upper, __low, base); \ + \ + __quot = __high; \ + __quot = __quot << 32 | __low; \ + (n) = __quot; \ + __mod; }) + +#else + +#define do_div64_32(res, high, low, base) ({ \ + unsigned long __quot, __mod, __r0; \ + \ + __asm__("dsll32 %2,%z3,0\n\t" \ + "or %2,%2,%z4\n\t" \ + "ddivu $0,%2,%z5" \ + : "=h" (__mod), "=l" (__quot), "=&r" (__r0) \ + : "Jr" (high), "Jr" (low), "Jr" (base)); \ + \ + (res) = __quot; \ + __mod; }) + +#define do_div(n, base) ({ \ + unsigned long long __quot; \ + unsigned long __mod, __r0; \ + \ + __quot = (n); \ + \ + __asm__("dsll32 %2,%M3,0\n\t" \ + "or %2,%2,%L3\n\t" \ + "ddivu $0,%2,%z4\n\t" \ + "mflo %L1\n\t" \ + "dsra32 %M1,%L1,0\n\t" \ + "dsll32 %L1,%L1,0\n\t" \ + "dsra32 %L1,%L1,0" \ + : "=h" (__mod), "=r" (__quot), "=&r" (__r0) \ + : "r" (n), "Jr" (base)); \ + \ + (n) = __quot; \ + __mod; }) + +#endif #endif /* _ASM_DIV64_H */ diff --git a/include/asm-mips/elf.h b/include/asm-mips/elf.h index adaba397ae2e..9f13f7299ce4 100644 --- a/include/asm-mips/elf.h +++ b/include/asm-mips/elf.h @@ -25,8 +25,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; int __res = 1; \ struct elfhdr *__h = (hdr); \ \ - if ((__h->e_machine != EM_MIPS) && \ - (__h->e_machine != EM_MIPS_RS4_BE)) \ + if (__h->e_machine != EM_MIPS) \ __res = 0; \ if (__h->e_flags & EF_MIPS_ARCH) \ __res = 0; \ @@ -35,17 +34,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; }) /* This one accepts IRIX binaries. */ -#define irix_elf_check_arch(hdr) \ -({ \ - int __res = 1; \ - struct elfhdr *__h = (hdr); \ - \ - if ((__h->e_machine != EM_MIPS) && \ - (__h->e_machine != EM_MIPS_RS4_BE)) \ - __res = 0; \ - \ - __res; \ -}) +#define irix_elf_check_arch(hdr) ((hdr)->e_machine == EM_MIPS) /* * These are used to set parameters in the core dumps. diff --git a/include/asm-mips/errno.h b/include/asm-mips/errno.h index 0763d0e99e31..2956e4ce3b84 100644 --- a/include/asm-mips/errno.h +++ b/include/asm-mips/errno.h @@ -1,11 +1,9 @@ /* - * include/asm-mips/errno.h - * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1995, 1999 by Ralf Baechle + * Copyright (C) 1995, 1999, 2001 by Ralf Baechle */ #ifndef _ASM_ERRNO_H #define _ASM_ERRNO_H diff --git a/include/asm-mips/fcntl.h b/include/asm-mips/fcntl.h index b14cc9063f14..f7a6ada7fffb 100644 --- a/include/asm-mips/fcntl.h +++ b/include/asm-mips/fcntl.h @@ -1,13 +1,12 @@ -/* $Id: fcntl.h,v 1.4 1998/09/19 19:19:36 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle */ -#ifndef __ASM_MIPS_FCNTL_H -#define __ASM_MIPS_FCNTL_H +#ifndef __ASM_FCNTL_H +#define __ASM_FCNTL_H /* open/fcntl - O_SYNC is only implemented on blocks devices and on files located on an ext2 file system */ @@ -44,6 +43,10 @@ #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#define F_GETLK64 33 /* using 'struct flock64' */ +#define F_SETLK64 34 +#define F_SETLKW64 35 + /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -76,10 +79,19 @@ typedef struct flock { short l_whence; __kernel_off_t l_start; __kernel_off_t l_len; - long l_sysid; /* XXXXXXXXXXXXXXXXXXXXXXXXX */ + long l_sysid; /* ABI junk, unused on Linux */ __kernel_pid_t l_pid; - long pad[4]; /* ZZZZZZZZZZZZZZZZZZZZZZZZZZ */ + long pad[4]; /* ABI junk, unused on Linux */ } flock_t; +typedef struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; + pid_t l_pid; +} flock64_t; + #define F_LINUX_SPECIFIC_BASE 1024 -#endif /* __ASM_MIPS_FCNTL_H */ + +#endif /* __ASM_FCNTL_H */ diff --git a/include/asm-mips/fpu_emulator.h b/include/asm-mips/fpu_emulator.h new file mode 100644 index 000000000000..70800480b87e --- /dev/null +++ b/include/asm-mips/fpu_emulator.h @@ -0,0 +1,44 @@ +/* + * Definitiona for the Algorithmics FPU Emulator port into MIPS Linux + */ +/************************************************************************** + * + * include/asm-mips/fpu_emulator.h + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + *************************************************************************/ +/* + * Further private data for which no space exists in mips_fpu_soft_struct. + * This should be subsumed into the mips_fpu_soft_struct structure as + * defined in processor.h as soon as the absurd wired absolute assembler + * offsets become dynamic at compile time. + */ + +struct mips_fpu_emulator_private { + unsigned int eir; + struct { + unsigned int emulated; + unsigned int loads; + unsigned int stores; + unsigned int cp1ops; + unsigned int cp1xops; + unsigned int errors; + } stats; +}; diff --git a/include/asm-mips/hardirq.h b/include/asm-mips/hardirq.h index eead2fb87e42..28340dff3f55 100644 --- a/include/asm-mips/hardirq.h +++ b/include/asm-mips/hardirq.h @@ -1,5 +1,4 @@ -/* $Id: hardirq.h,v 1.8 2000/03/02 02:37:13 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -13,6 +12,7 @@ #include <linux/config.h> #include <linux/threads.h> #include <linux/irq.h> +#include <linux/spinlock.h> /* entry.S is sensitive to the offsets of these fields */ typedef struct { @@ -38,14 +38,60 @@ typedef struct { #define hardirq_trylock(cpu) (local_irq_count(cpu) == 0) #define hardirq_endlock(cpu) do { } while (0) -#define irq_enter(cpu) (local_irq_count(cpu)++) -#define irq_exit(cpu) (local_irq_count(cpu)--) +#define irq_enter(cpu, irq) (local_irq_count(cpu)++) +#define irq_exit(cpu, irq) (local_irq_count(cpu)--) #define synchronize_irq() barrier(); #else -#error No habla MIPS SMP +#include <asm/atomic.h> +#include <linux/spinlock.h> +#include <asm/smp.h> + +extern int global_irq_holder; +extern spinlock_t global_irq_lock; + +static inline int irqs_running (void) +{ + int i; + + for (i = 0; i < smp_num_cpus; i++) + if (local_irq_count(i)) + return 1; + return 0; +} + +static inline void release_irqlock(int cpu) +{ + /* if we didn't own the irq lock, just ignore.. */ + if (global_irq_holder == cpu) { + global_irq_holder = NO_PROC_ID; + spin_unlock(&global_irq_lock); + } +} + +static inline int hardirq_trylock(int cpu) +{ + return !local_irq_count(cpu) && !spin_is_locked(&global_irq_lock); +} + +#define hardirq_endlock(cpu) do { } while (0) + +static inline void irq_enter(int cpu, int irq) +{ + ++local_irq_count(cpu); + + while (spin_is_locked(&global_irq_lock)) + barrier(); +} + +static inline void irq_exit(int cpu, int irq) +{ + --local_irq_count(cpu); +} + +extern void synchronize_irq(void); #endif /* CONFIG_SMP */ #endif /* _ASM_HARDIRQ_H */ diff --git a/include/asm-mips/hdreg.h b/include/asm-mips/hdreg.h index 189dfc55c3cb..4b90cf6bf98a 100644 --- a/include/asm-mips/hdreg.h +++ b/include/asm-mips/hdreg.h @@ -1,18 +1,15 @@ -/* $Id: hdreg.h,v 1.4 1998/05/08 21:05:26 davem Exp $ - * - * linux/include/asm-mips/hdreg.h - * +/* * Copyright (C) 1994-1996 Linus Torvalds & authors + * Copyright (C) 2001 Ralf Baechle */ /* * This file contains the MIPS architecture specific IDE code. */ -#ifndef __ASM_MIPS_HDREG_H -#define __ASM_MIPS_HDREG_H - -typedef unsigned short ide_ioreg_t; +#ifndef _ASM_HDREG_H +#define _ASM_HDREG_H -#endif /* __ASM_MIPS_HDREG_H */ +typedef unsigned long ide_ioreg_t; +#endif /* _ASM_HDREG_H */ diff --git a/include/asm-mips/hw_irq.h b/include/asm-mips/hw_irq.h index 1bf6629b4ee8..8dfa57d9be94 100644 --- a/include/asm-mips/hw_irq.h +++ b/include/asm-mips/hw_irq.h @@ -1,5 +1,16 @@ -/* This exists merely to satisfy <linux/irq.h>. There is - nothing that would go here of general interest. +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000, 2001 by Ralf Baechle + */ +#ifndef _ASM_HW_IRQ_H +#define _ASM_HW_IRQ_H - Everything of consequence is in arch/alpha/kernel/irq_impl.h, - to be used only in arch/alpha/kernel/. */ +/* This may not be apropriate for all machines, we'll see ... */ +static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) +{ +} + +#endif /* _ASM_HW_IRQ_H */ diff --git a/include/asm-mips/ide.h b/include/asm-mips/ide.h index ed20997b1ce3..10da72198120 100644 --- a/include/asm-mips/ide.h +++ b/include/asm-mips/ide.h @@ -8,16 +8,13 @@ * Copyright (C) 1994-1996 Linus Torvalds & authors */ -/* - * This file contains the MIPS architecture specific IDE code. - */ - #ifndef __ASM_IDE_H #define __ASM_IDE_H #ifdef __KERNEL__ #include <linux/config.h> +#include <asm/io.h> #ifndef MAX_HWIFS # ifdef CONFIG_BLK_DEV_IDEPCI @@ -93,13 +90,21 @@ static __inline__ void ide_init_default_hwifs(void) typedef union { unsigned all : 8; /* all of the bits together */ struct { +#ifdef __MIPSEB__ + unsigned bit7 : 1; /* always 1 */ + unsigned lba : 1; /* using LBA instead of CHS */ + unsigned bit5 : 1; /* always 1 */ + unsigned unit : 1; /* drive select number, 0 or 1 */ + unsigned head : 4; /* always zeros here */ +#else unsigned head : 4; /* always zeros here */ unsigned unit : 1; /* drive select number, 0 or 1 */ unsigned bit5 : 1; /* always 1 */ unsigned lba : 1; /* using LBA instead of CHS */ unsigned bit7 : 1; /* always 1 */ +#endif } b; - } select_t; +} select_t; static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *), unsigned long flags, const char *device, void *dev_id) @@ -129,11 +134,96 @@ static __inline__ void ide_release_region(ide_ioreg_t from, ide_ops->ide_release_region(from, extent); } +#undef SUPPORT_VLB_SYNC +#define SUPPORT_VLB_SYNC 0 + +#if defined(__MIPSEB__) + +#define T_CHAR (0x0000) /* char: don't touch */ +#define T_SHORT (0x4000) /* short: 12 -> 21 */ +#define T_INT (0x8000) /* int: 1234 -> 4321 */ +#define T_TEXT (0xc000) /* text: 12 -> 21 */ + +#define T_MASK_TYPE (0xc000) +#define T_MASK_COUNT (0x3fff) + +#define D_CHAR(cnt) (T_CHAR | (cnt)) +#define D_SHORT(cnt) (T_SHORT | (cnt)) +#define D_INT(cnt) (T_INT | (cnt)) +#define D_TEXT(cnt) (T_TEXT | (cnt)) + +static u_short driveid_types[] = { + D_SHORT(10), /* config - vendor2 */ + D_TEXT(20), /* serial_no */ + D_SHORT(3), /* buf_type - ecc_bytes */ + D_TEXT(48), /* fw_rev - model */ + D_CHAR(2), /* max_multsect - vendor3 */ + D_SHORT(1), /* dword_io */ + D_CHAR(2), /* vendor4 - capability */ + D_SHORT(1), /* reserved50 */ + D_CHAR(4), /* vendor5 - tDMA */ + D_SHORT(4), /* field_valid - cur_sectors */ + D_INT(1), /* cur_capacity */ + D_CHAR(2), /* multsect - multsect_valid */ + D_INT(1), /* lba_capacity */ + D_SHORT(194) /* dma_1word - reservedyy */ +}; + +#define num_driveid_types (sizeof(driveid_types)/sizeof(*driveid_types)) + +static __inline__ void ide_fix_driveid(struct hd_driveid *id) +{ + u_char *p = (u_char *)id; + int i, j, cnt; + u_char t; + + for (i = 0; i < num_driveid_types; i++) { + cnt = driveid_types[i] & T_MASK_COUNT; + switch (driveid_types[i] & T_MASK_TYPE) { + case T_CHAR: + p += cnt; + break; + case T_SHORT: + for (j = 0; j < cnt; j++) { + t = p[0]; + p[0] = p[1]; + p[1] = t; + p += 2; + } + break; + case T_INT: + for (j = 0; j < cnt; j++) { + t = p[0]; + p[0] = p[3]; + p[3] = t; + t = p[1]; + p[1] = p[2]; + p[2] = t; + p += 4; + } + break; + case T_TEXT: + for (j = 0; j < cnt; j += 2) { + t = p[0]; + p[0] = p[1]; + p[1] = t; + p += 2; + } + break; + }; + } +} + +#else /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__) */ + +#define ide_fix_driveid(id) do {} while (0) + +#endif + /* * The following are not needed for the non-m68k ports */ #define ide_ack_intr(hwif) (1) -#define ide_fix_driveid(id) do {} while (0) #define ide_release_lock(lock) do {} while (0) #define ide_get_lock(lock, hdlr, data) do {} while (0) diff --git a/include/asm-mips/inst.h b/include/asm-mips/inst.h index 8d7328f6d3d6..6ad517241768 100644 --- a/include/asm-mips/inst.h +++ b/include/asm-mips/inst.h @@ -5,10 +5,10 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996 by Ralf Baechle + * Copyright (C) 1996, 2000 by Ralf Baechle */ -#ifndef __ASM_MIPS_INST_H -#define __ASM_MIPS_INST_H +#ifndef _ASM_INST_H +#define _ASM_INST_H /* * Major opcodes; before MIPS IV cop1x was called cop3. @@ -21,7 +21,7 @@ enum major_op { cop0_op, cop1_op, cop2_op, cop1x_op, beql_op, bnel_op, blezl_op, bgtzl_op, daddi_op, daddiu_op, ldl_op, ldr_op, - major_1c_op, major_1d_op, major_1e_op, major_1f_op, + major_1c_op, jalx_op, major_1e_op, major_1f_op, lb_op, lh_op, lwl_op, lw_op, lbu_op, lhu_op, lwr_op, lwu_op, sb_op, sh_op, swl_op, sw_op, @@ -80,6 +80,13 @@ enum cop_op { }; /* + * rt field of cop.bc_op opcodes + */ +enum bcop_op { + bcf_op, bct_op, bcfl_op, bctl_op +}; + +/* * func field of cop0 coi opcodes. */ enum cop0_coi_func { @@ -301,4 +308,64 @@ union mips_instruction { struct ma_format ma_format; }; -#endif /* __ASM_MIPS_INST_H */ +/* HACHACHAHCAHC ... */ + +/* In case some other massaging is needed, keep MIPSInst as wrapper */ + +#define MIPSInst(x) x + +#define I_OPCODE_SFT 26 +#define MIPSInst_OPCODE(x) (MIPSInst(x) >> I_OPCODE_SFT) + +#define I_JTARGET_SFT 0 +#define MIPSInst_JTARGET(x) (MIPSInst(x) & 0x03ffffff) + +#define I_RS_SFT 21 +#define MIPSInst_RS(x) ((MIPSInst(x) & 0x03e00000) >> I_RS_SFT) + +#define I_RT_SFT 16 +#define MIPSInst_RT(x) ((MIPSInst(x) & 0x001f0000) >> I_RT_SFT) + +#define I_IMM_SFT 0 +#define MIPSInst_SIMM(x) ((int)((short)(MIPSInst(x) & 0xffff))) +#define MIPSInst_UIMM(x) (MIPSInst(x) & 0xffff) + +#define I_CACHEOP_SFT 18 +#define MIPSInst_CACHEOP(x) ((MIPSInst(x) & 0x001c0000) >> I_CACHEOP_SFT) + +#define I_CACHESEL_SFT 16 +#define MIPSInst_CACHESEL(x) ((MIPSInst(x) & 0x00030000) >> I_CACHESEL_SFT) + +#define I_RD_SFT 11 +#define MIPSInst_RD(x) ((MIPSInst(x) & 0x0000f800) >> I_RD_SFT) + +#define I_RE_SFT 6 +#define MIPSInst_RE(x) ((MIPSInst(x) & 0x000007c0) >> I_RE_SFT) + +#define I_FUNC_SFT 0 +#define MIPSInst_FUNC(x) (MIPSInst(x) & 0x0000003f) + +#define I_FFMT_SFT 21 +#define MIPSInst_FFMT(x) ((MIPSInst(x) & 0x01e00000) >> I_FFMT_SFT) + +#define I_FT_SFT 16 +#define MIPSInst_FT(x) ((MIPSInst(x) & 0x001f0000) >> I_FT_SFT) + +#define I_FS_SFT 11 +#define MIPSInst_FS(x) ((MIPSInst(x) & 0x0000f800) >> I_FS_SFT) + +#define I_FD_SFT 6 +#define MIPSInst_FD(x) ((MIPSInst(x) & 0x000007c0) >> I_FD_SFT) + +#define I_FR_SFT 21 +#define MIPSInst_FR(x) ((MIPSInst(x) & 0x03e00000) >> I_FR_SFT) + +#define I_FMA_FUNC_SFT 2 +#define MIPSInst_FMA_FUNC(x) ((MIPSInst(x) & 0x0000003c) >> I_FMA_FUNC_SFT) + +#define I_FMA_FFMT_SFT 0 +#define MIPSInst_FMA_FFMT(x) (MIPSInst(x) & 0x00000003) + +typedef unsigned int mips_instruction; + +#endif /* _ASM_INST_H */ diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h index 3af11a591730..2c96842a6277 100644 --- a/include/asm-mips/io.h +++ b/include/asm-mips/io.h @@ -1,5 +1,4 @@ -/* $Id: io.h,v 1.13 2000/02/24 00:13:19 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -7,16 +6,38 @@ * Copyright (C) 1994, 1995 Waldorf GmbH * Copyright (C) 1994 - 2000 Ralf Baechle * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 2000 FSMLabs, Inc. */ #ifndef _ASM_IO_H #define _ASM_IO_H +#include <linux/config.h> +#include <linux/pagemap.h> +#include <asm/addrspace.h> +#include <asm/byteorder.h> + /* * Slowdown I/O port space accesses for antique hardware. */ #undef CONF_SLOWDOWN_IO -#include <asm/addrspace.h> +/* + * Sane hardware offers swapping of I/O space accesses in hardware; less + * sane hardware forces software to fiddle with this ... + */ +#if defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__) + +#define __ioswab8(x) (x) +#define __ioswab16(x) swab16(x) +#define __ioswab32(x) swab32(x) + +#else + +#define __ioswab8(x) (x) +#define __ioswab16(x) (x) +#define __ioswab32(x) (x) + +#endif /* * This file contains the definitions for the MIPS counterpart of the @@ -91,9 +112,6 @@ extern inline void * phys_to_virt(unsigned long address) return (void *)KSEG0ADDR(address); } -extern void * ioremap(unsigned long phys_addr, unsigned long size); -extern void iounmap(void *addr); - /* * IO bus memory addresses are also 1:1 with the physical address */ @@ -113,54 +131,35 @@ extern inline void * bus_to_virt(unsigned long address) */ extern unsigned long isa_slot_offset; -/* - * readX/writeX() are used to access memory mapped devices. On some - * architectures the memory mapped IO stuff needs to be accessed - * differently. On the x86 architecture, we just read/write the - * memory location directly. - * - * On MIPS, we have the whole physical address space mapped at all - * times, so "ioremap()" and "iounmap()" do not need to do anything. - * (This isn't true for all machines but we still handle these cases - * with wired TLB entries anyway ...) - * - * We cheat a bit and always return uncachable areas until we've fixed - * the drivers to handle caching properly. - */ -extern inline void * ioremap(unsigned long offset, unsigned long size) -{ - return (void *) KSEG1ADDR(offset); -} +extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags); -/* - * This one maps high address device memory and turns off caching for that area. - * it's useful if some control registers are in such an area and write combining - * or read caching is not desirable: - */ -extern inline void * ioremap_nocache (unsigned long offset, unsigned long size) +extern inline void *ioremap(unsigned long offset, unsigned long size) { - return (void *) KSEG1ADDR(offset); + return __ioremap(offset, size, _CACHE_UNCACHED); } -extern inline void iounmap(void *addr) +extern inline void *ioremap_nocache(unsigned long offset, unsigned long size) { + return __ioremap(offset, size, _CACHE_UNCACHED); } +extern void iounmap(void *addr); + /* * XXX We need system specific versions of these to handle EISA address bits * 24-31 on SNI. * XXX more SNI hacks. */ #define readb(addr) (*(volatile unsigned char *)(addr)) -#define readw(addr) (*(volatile unsigned short *)(addr)) -#define readl(addr) (*(volatile unsigned int *)(addr)) +#define readw(addr) __ioswab16((*(volatile unsigned short *)(addr))) +#define readl(addr) __ioswab32((*(volatile unsigned int *)(addr))) #define __raw_readb readb #define __raw_readw readw #define __raw_readl readl #define writeb(b,addr) (*(volatile unsigned char *)(addr)) = (b) -#define writew(b,addr) (*(volatile unsigned short *)(addr)) = (b) -#define writel(b,addr) (*(volatile unsigned int *)(addr)) = (b) +#define writew(b,addr) (*(volatile unsigned short *)(addr)) = (__ioswab16(b)) +#define writel(b,addr) (*(volatile unsigned int *)(addr)) = (__ioswab32(b)) #define __raw_writeb writeb #define __raw_writew writew #define __raw_writel writel @@ -226,12 +225,12 @@ extern inline void __out##s(unsigned int value, unsigned int port) { #define __OUT2(m) \ __asm__ __volatile__ ("s" #m "\t%0,%1(%2)" -#define __OUT(m,s) \ -__OUT1(s) __OUT2(m) : : "r" (value), "i" (0), "r" (mips_io_port_base+port)); } \ -__OUT1(s##c) __OUT2(m) : : "r" (value), "ir" (port), "r" (mips_io_port_base)); } \ -__OUT1(s##_p) __OUT2(m) : : "r" (value), "i" (0), "r" (mips_io_port_base+port)); \ +#define __OUT(m,s,w) \ +__OUT1(s) __OUT2(m) : : "r" (__ioswab##w(value)), "i" (0), "r" (mips_io_port_base+port)); } \ +__OUT1(s##c) __OUT2(m) : : "r" (__ioswab##w(value)), "ir" (port), "r" (mips_io_port_base)); } \ +__OUT1(s##_p) __OUT2(m) : : "r" (__ioswab##w(value)), "i" (0), "r" (mips_io_port_base+port)); \ SLOW_DOWN_IO; } \ -__OUT1(s##c_p) __OUT2(m) : : "r" (value), "ir" (port), "r" (mips_io_port_base)); \ +__OUT1(s##c_p) __OUT2(m) : : "r" (__ioswab##w(value)), "ir" (port), "r" (mips_io_port_base)); \ SLOW_DOWN_IO; } #define __IN1(t,s) \ @@ -243,11 +242,11 @@ extern __inline__ t __in##s(unsigned int port) { t _v; #define __IN2(m) \ __asm__ __volatile__ ("l" #m "\t%0,%1(%2)" -#define __IN(t,m,s) \ -__IN1(t,s) __IN2(m) : "=r" (_v) : "i" (0), "r" (mips_io_port_base+port)); return _v; } \ -__IN1(t,s##c) __IN2(m) : "=r" (_v) : "ir" (port), "r" (mips_io_port_base)); return _v; } \ -__IN1(t,s##_p) __IN2(m) : "=r" (_v) : "i" (0), "r" (mips_io_port_base+port)); SLOW_DOWN_IO; return _v; } \ -__IN1(t,s##c_p) __IN2(m) : "=r" (_v) : "ir" (port), "r" (mips_io_port_base)); SLOW_DOWN_IO; return _v; } +#define __IN(t,m,s,w) \ +__IN1(t,s) __IN2(m) : "=r" (_v) : "i" (0), "r" (mips_io_port_base+port)); return __ioswab##w(_v); } \ +__IN1(t,s##c) __IN2(m) : "=r" (_v) : "ir" (port), "r" (mips_io_port_base)); return __ioswab##w(_v); } \ +__IN1(t,s##_p) __IN2(m) : "=r" (_v) : "i" (0), "r" (mips_io_port_base+port)); SLOW_DOWN_IO; return __ioswab##w(_v); } \ +__IN1(t,s##c_p) __IN2(m) : "=r" (_v) : "ir" (port), "r" (mips_io_port_base)); SLOW_DOWN_IO; return __ioswab##w(_v); } #define __INS1(s) \ extern inline void __ins##s(unsigned int port, void * addr, unsigned long count) { @@ -268,11 +267,13 @@ __asm__ __volatile__ ( \ #define __INS(m,s,i) \ __INS1(s) __INS2(m) \ : "=r" (addr), "=r" (count) \ - : "0" (addr), "1" (count), "i" (0), "r" (mips_io_port_base+port), "I" (i) \ + : "0" (addr), "1" (count), "i" (0), \ + "r" (mips_io_port_base+port), "I" (i) \ : "$1");} \ __INS1(s##c) __INS2(m) \ : "=r" (addr), "=r" (count) \ - : "0" (addr), "1" (count), "ir" (port), "r" (mips_io_port_base), "I" (i) \ + : "0" (addr), "1" (count), "ir" (port), \ + "r" (mips_io_port_base), "I" (i) \ : "$1");} #define __OUTS1(s) \ @@ -301,13 +302,13 @@ __OUTS1(s##c) __OUTS2(m) \ : "0" (addr), "1" (count), "ir" (port), "r" (mips_io_port_base), "I" (i) \ : "$1");} -__IN(unsigned char,b,b) -__IN(unsigned short,h,w) -__IN(unsigned int,w,l) +__IN(unsigned char,b,b,8) +__IN(unsigned short,h,w,16) +__IN(unsigned int,w,l,32) -__OUT(b,b) -__OUT(h,w) -__OUT(w,l) +__OUT(b,b,8) +__OUT(h,w,16) +__OUT(w,l,32) __INS(b,b,1) __INS(h,w,2) @@ -317,6 +318,7 @@ __OUTS(b,b,1) __OUTS(h,w,2) __OUTS(w,l,4) + /* * Note that due to the way __builtin_constant_p() works, you * - can't use it inside an inline function (it will never be true) diff --git a/include/asm-mips/ioctl.h b/include/asm-mips/ioctl.h index 360b22ce337e..ab54abc3d6db 100644 --- a/include/asm-mips/ioctl.h +++ b/include/asm-mips/ioctl.h @@ -5,7 +5,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1995, 1996 by Ralf Baechle + * Copyright (C) 1995, 1996, 2001 by Ralf Baechle */ #ifndef __ASM_MIPS_IOCTL_H #define __ASM_MIPS_IOCTL_H @@ -40,11 +40,6 @@ #define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) /* - * We to additionally limit parameters to a maximum 255 bytes. - */ -#define _IOC_SLMASK 0xff - -/* * Direction bits _IOC_NONE could be 0, but OSF/1 gives it a bit. * And this turns out useful to catch old ioctl numbers in header * files for us. @@ -65,7 +60,7 @@ (((dir) << _IOC_DIRSHIFT) | \ ((type) << _IOC_TYPESHIFT) | \ ((nr) << _IOC_NRSHIFT) | \ - (((size) & _IOC_SLMASK) << _IOC_SIZESHIFT)) + ((size) << _IOC_SIZESHIFT)) /* used to create numbers */ #define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) diff --git a/include/asm-mips/ioctls.h b/include/asm-mips/ioctls.h index 5e268a1c5787..59689c43076d 100644 --- a/include/asm-mips/ioctls.h +++ b/include/asm-mips/ioctls.h @@ -58,6 +58,7 @@ #define FIONCLEX 0x6602 /* these numbers need to be adjusted. */ #define FIOASYNC 0x667d #define FIONBIO 0x667e +#define FIOQSIZE 0x667f #if defined(__USE_MISC) || defined (__KERNEL__) #define TIOCGLTC (tIOC | 116) /* get special local chars */ diff --git a/include/asm-mips/irq.h b/include/asm-mips/irq.h index c7bafd3c879f..f89e071c355a 100644 --- a/include/asm-mips/irq.h +++ b/include/asm-mips/irq.h @@ -1,25 +1,39 @@ -/* $Id: irq.h,v 1.6 2000/01/26 00:07:45 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1994 by Waldorf GMBH, written by Ralf Baechle - * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle + * Copyright (C) 1995, 96, 97, 98, 99, 2000, 2001 by Ralf Baechle */ #ifndef _ASM_IRQ_H #define _ASM_IRQ_H -#define NR_IRQS 64 +#include <linux/config.h> + +#define NR_IRQS 64 /* Largest number of ints of all machines. */ #define TIMER_IRQ 0 -extern int (*irq_cannonicalize)(int irq); +#ifdef CONFIG_I8259 +static inline int irq_cannonicalize(int irq) +{ + return ((irq == 2) ? 9 : irq); +} +#else +#define irq_cannonicalize(irq) (irq) /* Sane hardware, sane code ... */ +#endif struct irqaction; extern int i8259_setup_irq(int irq, struct irqaction * new); extern void disable_irq(unsigned int); + +#ifdef CONFIG_ROTTEN_IRQ #define disable_irq_nosync disable_irq +#else +extern void disable_irq_nosync(unsigned int); +#endif + extern void enable_irq(unsigned int); /* Machine specific interrupt initialization */ diff --git a/include/asm-mips/jazzdma.h b/include/asm-mips/jazzdma.h index 634cfecd38af..0a205b77e505 100644 --- a/include/asm-mips/jazzdma.h +++ b/include/asm-mips/jazzdma.h @@ -1,29 +1,28 @@ /* * Helpfile for jazzdma.c -- Mips Jazz R4030 DMA controller support - * - * $Id:$ */ -#ifndef __ASM_MIPS_JAZZDMA_H -#define __ASM_MIPS_JAZZDMA_H +#ifndef _ASM_JAZZDMA_H +#define _ASM_JAZZDMA_H /* * Prototypes and macros */ -unsigned long vdma_init(unsigned long memory_start, unsigned long memory_end); -unsigned long vdma_alloc(unsigned long paddr, unsigned long size); -int vdma_free(unsigned long laddr); -int vdma_remap(unsigned long laddr, unsigned long paddr, unsigned long size); -unsigned long vdma_phys2log(unsigned long paddr); -unsigned long vdma_log2phys(unsigned long laddr); -void vdma_stats(void); /* for debugging only */ +extern void vdma_init(void); +extern unsigned long vdma_alloc(unsigned long paddr, unsigned long size); +extern int vdma_free(unsigned long laddr); +extern int vdma_remap(unsigned long laddr, unsigned long paddr, + unsigned long size); +extern unsigned long vdma_phys2log(unsigned long paddr); +extern unsigned long vdma_log2phys(unsigned long laddr); +extern void vdma_stats(void); /* for debugging only */ -void vdma_enable(int channel); -void vdma_disable(int channel); -void vdma_set_mode(int channel, int mode); -void vdma_set_addr(int channel, long addr); -void vdma_set_count(int channel, int count); -int vdma_get_residue(int channel); -int vdma_get_enable(int channel); +extern void vdma_enable(int channel); +extern void vdma_disable(int channel); +extern void vdma_set_mode(int channel, int mode); +extern void vdma_set_addr(int channel, long addr); +extern void vdma_set_count(int channel, int count); +extern int vdma_get_residue(int channel); +extern int vdma_get_enable(int channel); /* * some definitions used by the driver functions @@ -49,8 +48,7 @@ int vdma_get_enable(int channel); /* * VDMA pagetable entry description */ -typedef volatile struct VDMA_PGTBL_ENTRY -{ +typedef volatile struct VDMA_PGTBL_ENTRY { unsigned int frame; /* physical frame no. */ unsigned int owner; /* owner of this entry (0=free) */ } VDMA_PGTBL_ENTRY; @@ -95,4 +93,4 @@ typedef volatile struct VDMA_PGTBL_ENTRY #define R4030_MODE_BURST (1<<6) /* Rev. 2 only */ #define R4030_MODE_FAST_ACK (1<<7) /* Rev. 2 only */ -#endif /* __ASM_MIPS_JAZZDMA_H */ +#endif /* _ASM_JAZZDMA_H */ diff --git a/include/asm-mips/keyboard.h b/include/asm-mips/keyboard.h index 7baed2d8c0b1..54d6d07fa6fb 100644 --- a/include/asm-mips/keyboard.h +++ b/include/asm-mips/keyboard.h @@ -13,10 +13,13 @@ #include <linux/delay.h> #include <linux/ioport.h> +#include <linux/config.h> #include <asm/bootinfo.h> #define DISABLE_KBD_DURING_INTERRUPTS 0 +#ifdef CONFIG_PC_KEYB + extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, @@ -35,6 +38,19 @@ extern void kbd_forward_char (int ch); #define kbd_init_hw pckbd_init_hw #define kbd_sysrq_xlate pckbd_sysrq_xlate +#else + +extern int kbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int kbd_getkeycode(unsigned int scancode); +extern int kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char kbd_unexpected_up(unsigned char keycode); +extern void kbd_leds(unsigned char leds); +extern void kbd_init_hw(void); +extern unsigned char *kbd_sysrq_xlate; + +#endif + #define SYSRQ_KEY 0x54 /* Some stoneage hardware needs delays after some operations. */ diff --git a/include/asm-mips/mc146818rtc.h b/include/asm-mips/mc146818rtc.h index f521b7239ad3..6e23e432f335 100644 --- a/include/asm-mips/mc146818rtc.h +++ b/include/asm-mips/mc146818rtc.h @@ -14,8 +14,12 @@ #include <asm/io.h> #ifndef RTC_PORT +#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) +#define RTC_PORT(x) (0x14014800 + (x)) +#else #define RTC_PORT(x) (0x70 + (x)) #endif +#endif /* * The yet supported machines all access the RTC index register via @@ -45,8 +49,13 @@ extern struct rtc_ops *rtc_ops; #ifdef CONFIG_DECSTATION #define RTC_IRQ 0 +#elif defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) +#include <asm/it8172/it8172_int.h> +#define RTC_IRQ IT8172_RTC_IRQ #else #define RTC_IRQ 8 #endif +#define RTC_DEC_YEAR 0x3f /* Where we store the real year on DECs. */ + #endif /* _ASM_MC146818RTC_H */ diff --git a/include/asm-mips/mips32_cache.h b/include/asm-mips/mips32_cache.h new file mode 100644 index 000000000000..2de18bd7cb71 --- /dev/null +++ b/include/asm-mips/mips32_cache.h @@ -0,0 +1,288 @@ +/* + * mips32_cache.h + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * Inline assembly cache operations. + * + * This file is the original r4cache.c file with modification that makes the + * cache handling more generic. + * + * FIXME: Handle split L2 caches. + * + */ +#ifndef _MIPS_R4KCACHE_H +#define _MIPS_R4KCACHE_H + +#include <asm/asm.h> +#include <asm/cacheops.h> + +extern inline void flush_icache_line_indexed(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Index_Invalidate_I)); +} + +extern inline void flush_dcache_line_indexed(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Index_Writeback_Inv_D)); +} + +extern inline void flush_scache_line_indexed(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Index_Writeback_Inv_SD)); +} + +extern inline void flush_icache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Hit_Invalidate_I)); +} + +extern inline void flush_dcache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Hit_Writeback_Inv_D)); +} + +extern inline void invalidate_dcache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Hit_Invalidate_D)); +} + +extern inline void invalidate_scache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Hit_Invalidate_SD)); +} + +extern inline void flush_scache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Hit_Writeback_Inv_SD)); +} + +/* + * The next two are for badland addresses like signal trampolines. + */ +extern inline void protected_flush_icache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n" + "1:\tcache %1,(%0)\n" + "2:\t.set mips0\n\t" + ".set reorder\n\t" + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,2b\n\t" + ".previous" + : + : "r" (addr), + "i" (Hit_Invalidate_I)); +} + +extern inline void protected_writeback_dcache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n" + "1:\tcache %1,(%0)\n" + "2:\t.set mips0\n\t" + ".set reorder\n\t" + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,2b\n\t" + ".previous" + : + : "r" (addr), + "i" (Hit_Writeback_D)); +} + +#define cache_unroll(base,op) \ + __asm__ __volatile__(" \ + .set noreorder; \ + .set mips3; \ + cache %1, (%0); \ + .set mips0; \ + .set reorder" \ + : \ + : "r" (base), \ + "i" (op)); + + +extern inline void blast_dcache(void) +{ + unsigned long start = KSEG0; + unsigned long end = (start + dcache_size); + + while(start < end) { + cache_unroll(start,Index_Writeback_Inv_D); + start += dc_lsize; + } +} + +extern inline void blast_dcache_page(unsigned long page) +{ + unsigned long start = page; + unsigned long end = (start + PAGE_SIZE); + + while(start < end) { + cache_unroll(start,Hit_Writeback_Inv_D); + start += dc_lsize; + } +} + +extern inline void blast_dcache_page_indexed(unsigned long page) +{ + unsigned long start = page; + unsigned long end = (start + PAGE_SIZE); + + while(start < end) { + cache_unroll(start,Index_Writeback_Inv_D); + start += dc_lsize; + } +} + +extern inline void blast_icache(void) +{ + unsigned long start = KSEG0; + unsigned long end = (start + icache_size); + + while(start < end) { + cache_unroll(start,Index_Invalidate_I); + start += ic_lsize; + } +} + +extern inline void blast_icache_page(unsigned long page) +{ + unsigned long start = page; + unsigned long end = (start + PAGE_SIZE); + + while(start < end) { + cache_unroll(start,Hit_Invalidate_I); + start += ic_lsize; + } +} + +extern inline void blast_icache_page_indexed(unsigned long page) +{ + unsigned long start = page; + unsigned long end = (start + PAGE_SIZE); + + while(start < end) { + cache_unroll(start,Index_Invalidate_I); + start += ic_lsize; + } +} + +extern inline void blast_scache(void) +{ + unsigned long start = KSEG0; + unsigned long end = KSEG0 + scache_size; + + while(start < end) { + cache_unroll(start,Index_Writeback_Inv_SD); + start += sc_lsize; + } +} + +extern inline void blast_scache_page(unsigned long page) +{ + unsigned long start = page; + unsigned long end = page + PAGE_SIZE; + + while(start < end) { + cache_unroll(start,Hit_Writeback_Inv_SD); + start += sc_lsize; + } +} + +extern inline void blast_scache_page_indexed(unsigned long page) +{ + unsigned long start = page; + unsigned long end = page + PAGE_SIZE; + + while(start < end) { + cache_unroll(start,Index_Writeback_Inv_SD); + start += sc_lsize; + } +} + +#endif /* !(_MIPS_R4KCACHE_H) */ diff --git a/include/asm-mips/mipsregs.h b/include/asm-mips/mipsregs.h index 4991babbde0a..0c67d0d127ac 100644 --- a/include/asm-mips/mipsregs.h +++ b/include/asm-mips/mipsregs.h @@ -1,14 +1,16 @@ -/* $Id: mipsregs.h,v 1.6 1999/07/26 19:42:43 harald Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1994, 1995, 1996, 1997 by Ralf Baechle + * Copyright (C) 1994, 1995, 1996, 1997, 2000, 2001 by Ralf Baechle + * Copyright (C) 2000 Silicon Graphics, Inc. * Modified for further R[236]000 support by Paul M. Antoine, 1996. + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. */ -#ifndef __ASM_MIPS_MIPSREGS_H -#define __ASM_MIPS_MIPSREGS_H +#ifndef _ASM_MIPSREGS_H +#define _ASM_MIPSREGS_H #include <linux/linkage.h> @@ -70,6 +72,12 @@ #define CP0_IWATCH $18 #define CP0_DWATCH $19 +/* + * Coprocessor 0 Set 1 register names + */ +#define CP0_S1_DERRADDR0 $26 +#define CP0_S1_DERRADDR1 $27 +#define CP0_S1_INTCONTROL $20 /* * Coprocessor 1 (FPU) register names */ @@ -77,6 +85,58 @@ #define CP1_STATUS $31 /* + * FPU Status Register Values + */ +/* + * Status Register Values + */ + +#define FPU_CSR_FLUSH 0x01000000 /* flush denormalised results to 0 */ +#define FPU_CSR_COND 0x00800000 /* $fcc0 */ +#define FPU_CSR_COND0 0x00800000 /* $fcc0 */ +#define FPU_CSR_COND1 0x02000000 /* $fcc1 */ +#define FPU_CSR_COND2 0x04000000 /* $fcc2 */ +#define FPU_CSR_COND3 0x08000000 /* $fcc3 */ +#define FPU_CSR_COND4 0x10000000 /* $fcc4 */ +#define FPU_CSR_COND5 0x20000000 /* $fcc5 */ +#define FPU_CSR_COND6 0x40000000 /* $fcc6 */ +#define FPU_CSR_COND7 0x80000000 /* $fcc7 */ + +/* + * X the exception cause indicator + * E the exception enable + * S the sticky/flag bit +*/ +#define FPU_CSR_ALL_X 0x0003f000 +#define FPU_CSR_UNI_X 0x00020000 +#define FPU_CSR_INV_X 0x00010000 +#define FPU_CSR_DIV_X 0x00008000 +#define FPU_CSR_OVF_X 0x00004000 +#define FPU_CSR_UDF_X 0x00002000 +#define FPU_CSR_INE_X 0x00001000 + +#define FPU_CSR_ALL_E 0x00000f80 +#define FPU_CSR_INV_E 0x00000800 +#define FPU_CSR_DIV_E 0x00000400 +#define FPU_CSR_OVF_E 0x00000200 +#define FPU_CSR_UDF_E 0x00000100 +#define FPU_CSR_INE_E 0x00000080 + +#define FPU_CSR_ALL_S 0x0000007c +#define FPU_CSR_INV_S 0x00000040 +#define FPU_CSR_DIV_S 0x00000020 +#define FPU_CSR_OVF_S 0x00000010 +#define FPU_CSR_UDF_S 0x00000008 +#define FPU_CSR_INE_S 0x00000004 + +/* rounding mode */ +#define FPU_CSR_RN 0x0 /* nearest */ +#define FPU_CSR_RZ 0x1 /* towards zero */ +#define FPU_CSR_RU 0x2 /* towards +Infinity */ +#define FPU_CSR_RD 0x3 /* towards -Infinity */ + + +/* * Values for PageMask register */ #define PM_4K 0x00000000 @@ -111,6 +171,16 @@ : "=r" (__res)); \ __res;}) +#define read_32bit_cp0_set1_register(source) \ +({ int __res; \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\treorder\n\t" \ + "cfc0\t%0,"STR(source)"\n\t" \ + ".set\tpop" \ + : "=r" (__res)); \ + __res;}) + /* * For now use this only with interrupts disabled! */ @@ -129,12 +199,36 @@ "nop" \ : : "r" (value)); +#define write_32bit_cp0_set1_register(register,value) \ + __asm__ __volatile__( \ + "ctc0\t%0,"STR(register)"\n\t" \ + "nop" \ + : : "r" (value)); + #define write_64bit_cp0_register(register,value) \ __asm__ __volatile__( \ ".set\tmips3\n\t" \ "dmtc0\t%0,"STR(register)"\n\t" \ ".set\tmips0" \ : : "r" (value)) + +#ifdef CONFIG_CPU_MIPS32 +/* + * This should be changed when we get a compiler that support the MIPS32 ISA. + */ +#define read_mips32_cp0_config1() \ +({ int __res; \ + __asm__ __volatile__( \ + ".set\tnoreorder\n\t" \ + ".set\tnoat\n\t" \ + ".word\t0x40018001\n\t" \ + "move\t%0,$1\n\t" \ + ".set\tat\n\t" \ + ".set\treorder" \ + :"=r" (__res)); \ + __res;}) +#endif + /* * R4x00 interrupt enable / cause bits */ @@ -166,7 +260,31 @@ */ #define __BUILD_SET_CP0(name,register) \ extern __inline__ unsigned int \ -set_cp0_##name(unsigned int change, unsigned int new) \ +set_cp0_##name(unsigned int set) \ +{ \ + unsigned int res; \ + \ + res = read_32bit_cp0_register(register); \ + res |= set; \ + write_32bit_cp0_register(register, res); \ + \ + return res; \ +} \ + \ +extern __inline__ unsigned int \ +clear_cp0_##name(unsigned int clear) \ +{ \ + unsigned int res; \ + \ + res = read_32bit_cp0_register(register); \ + res &= ~clear; \ + write_32bit_cp0_register(register, res); \ + \ + return res; \ +} \ + \ +extern __inline__ unsigned int \ +change_cp0_##name(unsigned int change, unsigned int new) \ { \ unsigned int res; \ \ @@ -186,42 +304,6 @@ __BUILD_SET_CP0(config,CP0_CONFIG) #endif /* defined (_LANGUAGE_ASSEMBLY) */ /* - * Inline code for use of the ll and sc instructions - * - * FIXME: This instruction is only available on MIPS ISA >=2. - * Since these operations are only being used for atomic operations - * the easiest workaround for the R[23]00 is to disable interrupts. - * This fails for R3000 SMP machines which use that many different - * technologies as replacement that it is difficult to create even - * just a hook for for all machines to hook into. The only good - * thing is that there is currently no R3000 SMP machine on the - * Linux/MIPS target list ... - */ -#define load_linked(addr) \ -({ \ - unsigned int __res; \ - \ - __asm__ __volatile__( \ - "ll\t%0,(%1)" \ - : "=r" (__res) \ - : "r" ((unsigned long) (addr))); \ - \ - __res; \ -}) - -#define store_conditional(addr,value) \ -({ \ - int __res; \ - \ - __asm__ __volatile__( \ - "sc\t%0,(%2)" \ - : "=r" (__res) \ - : "0" (value), "r" (addr)); \ - \ - __res; \ -}) - -/* * Bitfields in the R4xx0 cp0 status register */ #define ST0_IE 0x00000001 @@ -253,11 +335,44 @@ __BUILD_SET_CP0(config,CP0_CONFIG) /* * Bits specific to the R4640/R4650 */ -#define ST0_UM <1 << 4) +#define ST0_UM (1 << 4) #define ST0_IL (1 << 23) #define ST0_DL (1 << 24) /* + * Bitfields in the TX39 family CP0 Configuration Register 3 + */ +#define TX39_CONF_ICS_SHIFT 19 +#define TX39_CONF_ICS_MASK 0x00380000 +#define TX39_CONF_ICS_1KB 0x00000000 +#define TX39_CONF_ICS_2KB 0x00080000 +#define TX39_CONF_ICS_4KB 0x00100000 +#define TX39_CONF_ICS_8KB 0x00180000 +#define TX39_CONF_ICS_16KB 0x00200000 + +#define TX39_CONF_DCS_SHIFT 16 +#define TX39_CONF_DCS_MASK 0x00070000 +#define TX39_CONF_DCS_1KB 0x00000000 +#define TX39_CONF_DCS_2KB 0x00010000 +#define TX39_CONF_DCS_4KB 0x00020000 +#define TX39_CONF_DCS_8KB 0x00030000 +#define TX39_CONF_DCS_16KB 0x00040000 + +#define TX39_CONF_CWFON 0x00004000 +#define TX39_CONF_WBON 0x00002000 +#define TX39_CONF_RF_SHIFT 10 +#define TX39_CONF_RF_MASK 0x00000c00 +#define TX39_CONF_DOZE 0x00000200 +#define TX39_CONF_HALT 0x00000100 +#define TX39_CONF_LOCK 0x00000080 +#define TX39_CONF_ICE 0x00000020 +#define TX39_CONF_DCE 0x00000010 +#define TX39_CONF_IRSIZE_SHIFT 2 +#define TX39_CONF_IRSIZE_MASK 0x0000000c +#define TX39_CONF_DRSIZE_SHIFT 0 +#define TX39_CONF_DRSIZE_MASK 0x00000003 + +/* * Status register bits available in all MIPS CPUs. */ #define ST0_IM 0x0000ff00 @@ -277,6 +392,22 @@ __BUILD_SET_CP0(config,CP0_CONFIG) #define STATUSF_IP6 (1 << 14) #define STATUSB_IP7 15 #define STATUSF_IP7 (1 << 15) +#define STATUSB_IP8 0 +#define STATUSF_IP8 (1 << 0) +#define STATUSB_IP9 1 +#define STATUSF_IP9 (1 << 1) +#define STATUSB_IP10 2 +#define STATUSF_IP10 (1 << 2) +#define STATUSB_IP11 3 +#define STATUSF_IP11 (1 << 3) +#define STATUSB_IP12 4 +#define STATUSF_IP12 (1 << 4) +#define STATUSB_IP13 5 +#define STATUSF_IP13 (1 << 5) +#define STATUSB_IP14 6 +#define STATUSF_IP14 (1 << 6) +#define STATUSB_IP15 7 +#define STATUSF_IP15 (1 << 7) #define ST0_CH 0x00040000 #define ST0_SR 0x00100000 #define ST0_BEV 0x00400000 @@ -405,4 +536,4 @@ extern asmlinkage unsigned int read_perf_cntl(unsigned int counter); extern asmlinkage void write_perf_cntl(unsigned int counter, unsigned int val); #endif -#endif /* __ASM_MIPS_MIPSREGS_H */ +#endif /* _ASM_MIPSREGS_H */ diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h index 9be6976e896d..1e8e9614a012 100644 --- a/include/asm-mips/mmu_context.h +++ b/include/asm-mips/mmu_context.h @@ -1,5 +1,4 @@ -/* $Id: mmu_context.h,v 1.7 2000/02/04 07:40:53 ralf Exp $ - * +/* * Switch a MMU context. * * This file is subject to the terms and conditions of the GNU General Public @@ -13,11 +12,12 @@ #define _ASM_MMU_CONTEXT_H #include <linux/config.h> +#include <linux/slab.h> #include <asm/pgalloc.h> /* Fuck. The f-word is here so you can grep for it :-) */ extern unsigned long asid_cache; -extern pgd_t *current_pgd; +extern pgd_t *current_pgd[]; #if defined(CONFIG_CPU_R3000) @@ -60,7 +60,19 @@ get_new_mmu_context(struct mm_struct *mm, unsigned long asid) extern inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { +#ifndef CONFIG_SMP mm->context = 0; +#else + mm->context = (unsigned long)kmalloc(smp_num_cpus * + sizeof(unsigned long), GFP_KERNEL); + /* + * Init the "context" values so that a tlbpid allocation + * happens on the first switch. + */ + if (mm->context == 0) + return -ENOMEM; + memset((void *)mm->context, 0, smp_num_cpus * sizeof(unsigned long)); +#endif return 0; } @@ -73,7 +85,7 @@ extern inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, if ((next->context ^ asid) & ASID_VERSION_MASK) get_new_mmu_context(next, asid); - current_pgd = next->pgd; + current_pgd[cpu] = next->pgd; set_entryhi(next->context); } @@ -96,7 +108,7 @@ activate_mm(struct mm_struct *prev, struct mm_struct *next) /* Unconditionally get a new ASID. */ get_new_mmu_context(next, asid_cache); - current_pgd = next->pgd; + current_pgd[smp_processor_id()] = next->pgd; set_entryhi(next->context); } diff --git a/include/asm-mips/orion.h b/include/asm-mips/orion.h deleted file mode 100644 index 6df02086a64d..000000000000 --- a/include/asm-mips/orion.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Orion/Galileo specific header file. - * -- Cort <cort@fsmlabs.com> - */ -#ifndef __LINUX_MIPS_ORION_H -#define __LINUX_MIPS_ORION_H - -/* base address for the GT-64120 internal registers */ -#define GT64120_BASE (0x14000000) -/* GT64120 and PCI_0 interrupt cause register */ -#define GT64120_CAUSE_LOW *(unsigned long *)(GT64120_BASE + 0xc18) -#define GT64120_CAUSE_HIGH *(unsigned long *)(GT64120_BASE + 0xc1c) - -#endif /* __LINUX_MIPS_ORION_H */ diff --git a/include/asm-mips/param.h b/include/asm-mips/param.h index 5487778ca7b9..d4e4c7d73316 100644 --- a/include/asm-mips/param.h +++ b/include/asm-mips/param.h @@ -64,4 +64,8 @@ #define MAXHOSTNAMELEN 64 /* max length of hostname */ +#ifdef __KERNEL__ +# define CLOCKS_PER_SEC 100 /* frequency at which times() counts */ +#endif + #endif /* _ASM_PARAM_H */ diff --git a/include/asm-mips/pci.h b/include/asm-mips/pci.h index 2bbffa9b94f6..fdcedada3c14 100644 --- a/include/asm-mips/pci.h +++ b/include/asm-mips/pci.h @@ -1,5 +1,4 @@ -/* $Id: pci.h,v 1.10 2000/03/23 02:26:00 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -13,7 +12,8 @@ already-configured bus numbers - to be used for buggy BIOSes or architectures with incomplete PCI setup by the loader */ -#define pcibios_assign_all_busses() 0 +//#define pcibios_assign_all_busses() 0 +#define pcibios_assign_all_busses() 1 #define PCIBIOS_MIN_IO 0x1000 #define PCIBIOS_MIN_MEM 0x10000000 @@ -201,8 +201,27 @@ extern inline void pci_dma_sync_sg(struct pci_dev *hwdev, #endif } -/* Return the index of the PCI controller for device PDEV. */ -#define pci_controller_num(PDEV) (0) +/* Return whether the given PCI device DMA address mask can + * be supported properly. For example, if your device can + * only drive the low 24-bits during PCI bus mastering, then + * you would pass 0x00ffffff as the mask to this function. + */ +extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +{ + /* + * we fall back to GFP_DMA when the mask isn't all 1s, + * so we can't guarantee allocations that must be + * within a tighter range than GFP_DMA.. + */ + if (mask < 0x00ffffff) + return 0; + + return 1; +} + + +/* Return the index of the PCI controller for device. */ +#define pci_controller_num(pdev) (0) /* * These macros should be used after a pci_map_sg call has been done diff --git a/include/asm-mips/pgalloc.h b/include/asm-mips/pgalloc.h index e70b32fcbc89..66c12260fe6d 100644 --- a/include/asm-mips/pgalloc.h +++ b/include/asm-mips/pgalloc.h @@ -1,16 +1,16 @@ -/* $Id: pgalloc.h,v 1.3 2000/02/23 00:41:38 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1994 - 2000 by Ralf Baechle at alii + * Copyright (C) 1994 - 2001 by Ralf Baechle * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ #ifndef _ASM_PGALLOC_H #define _ASM_PGALLOC_H #include <linux/config.h> +#include <linux/mm.h> /* TLB flushing: * @@ -33,9 +33,7 @@ extern inline void flush_tlb_pgtables(struct mm_struct *mm, /* - * Allocate and free page tables. The xxx_kernel() versions are - * used to allocate a kernel page table - this turns on ASN bits - * if any. + * Allocate and free page tables. */ #define pgd_quicklist (current_cpu_data.pgd_quick) @@ -43,6 +41,13 @@ extern inline void flush_tlb_pgtables(struct mm_struct *mm, #define pte_quicklist (current_cpu_data.pte_quick) #define pgtable_cache_size (current_cpu_data.pgtable_cache_sz) +#define pmd_populate(mm, pmd, pte) pmd_set(pmd, pte) + +/* + * Initialize new page directory with pointers to invalid ptes + */ +extern void pgd_init(unsigned long page); + extern __inline__ pgd_t *get_pgd_slow(void) { pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL), *init; @@ -82,7 +87,6 @@ extern __inline__ void free_pgd_slow(pgd_t *pgd) } extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); -extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted); extern __inline__ pte_t *get_pte_fast(void) { @@ -123,94 +127,54 @@ extern __inline__ void free_pmd_slow(pmd_t *pmd) } extern void __bad_pte(pmd_t *pmd); -extern void __bad_pte_kernel(pmd_t *pmd); -#define pte_free_kernel(pte) free_pte_fast(pte) -#define pte_free(pte) free_pte_fast(pte) -#define pgd_free(pgd) free_pgd_fast(pgd) -#define pgd_alloc(mm) get_pgd_fast() - -extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address) +static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) { - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - - if (pmd_none(*pmd)) { - pte_t *page = get_pte_fast(); - if (page) { - pmd_val(*pmd) = (unsigned long)page; - return page + address; - } - return get_pte_kernel_slow(pmd, address); - } - if (pmd_bad(*pmd)) { - __bad_pte_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; + pte_t *pte; + + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pte) + clear_page(pte); + return pte; } -extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address) +static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - - if (pmd_none(*pmd)) { - pte_t *page = get_pte_fast(); - if (page) { - pmd_val(*pmd) = (unsigned long)page; - return page + address; - } - return get_pte_slow(pmd, address); - } - if (pmd_bad(*pmd)) { - __bad_pte(pmd); - return NULL; + unsigned long *ret; + + if ((ret = (unsigned long *)pte_quicklist) != NULL) { + pte_quicklist = (unsigned long *)(*ret); + ret[0] = ret[1]; + pgtable_cache_size--; } - return (pte_t *) pmd_page(*pmd) + address; + return (pte_t *)ret; } -/* - * allocating and freeing a pmd is trivial: the 1-entry pmd is - * inside the pgd, so has no extra memory associated with it. - */ -extern inline void pmd_free(pmd_t * pmd) +extern __inline__ void pte_free_fast(pte_t *pte) { + *(unsigned long *)pte = (unsigned long) pte_quicklist; + pte_quicklist = (unsigned long *) pte; + pgtable_cache_size++; } -extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address) +extern __inline__ void pte_free_slow(pte_t *pte) { - return (pmd_t *) pgd; + free_page((unsigned long)pte); } -#define pmd_free_kernel pmd_free -#define pmd_alloc_kernel pmd_alloc +#define pte_free(pte) pte_free_slow(pte) +#define pgd_free(pgd) free_pgd_fast(pgd) +#define pgd_alloc(mm) get_pgd_fast() -extern int do_check_pgt_cache(int, int); +/* + * allocating and freeing a pmd is trivial: the 1-entry pmd is + * inside the pgd, so has no extra memory associated with it. + */ +#define pmd_alloc_one_fast(mm, addr) ({ BUG(); ((pmd_t *)1); }) +#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) +#define pmd_free(x) do { } while (0) +#define pgd_populate(mm, pmd, pte) BUG() -extern inline void set_pgdir(unsigned long address, pgd_t entry) -{ - struct task_struct * p; - pgd_t *pgd; -#ifdef CONFIG_SMP - int i; -#endif - - read_lock(&tasklist_lock); - for_each_task(p) { - if (!p->mm) - continue; - *pgd_offset(p->mm,address) = entry; - } - read_unlock(&tasklist_lock); -#ifndef CONFIG_SMP - for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd) - pgd[address >> PGDIR_SHIFT] = entry; -#else - /* To pgd_alloc/pgd_free, one holds master kernel lock and so does our - callee, so we can modify pgd caches of other CPUs as well. -jj */ - for (i = 0; i < NR_CPUS; i++) - for (pgd = (pgd_t *)cpu_data[i].pgd_quick; pgd; pgd = (pgd_t *)*(unsigned long *)pgd) - pgd[address >> PGDIR_SHIFT] = entry; -#endif -} +extern int do_check_pgt_cache(int, int); #endif /* _ASM_PGALLOC_H */ diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h index 9cb9241c2b39..c96dea2e3619 100644 --- a/include/asm-mips/pgtable.h +++ b/include/asm-mips/pgtable.h @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1994 - 1999 by Ralf Baechle at alii + * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000 by Ralf Baechle at alii * Copyright (C) 1999 Silicon Graphics, Inc. */ #ifndef _ASM_PGTABLE_H @@ -25,32 +25,32 @@ * - flush_cache_page(mm, vmaddr) flushes a single page * - flush_cache_range(mm, start, end) flushes a range of pages * - flush_page_to_ram(page) write back kernel page to ram + * - flush_icache_range(start, end) flush a range of instructions */ extern void (*_flush_cache_all)(void); +extern void (*___flush_cache_all)(void); extern void (*_flush_cache_mm)(struct mm_struct *mm); extern void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start, unsigned long end); extern void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page); extern void (*_flush_cache_sigtramp)(unsigned long addr); extern void (*_flush_page_to_ram)(struct page * page); +extern void (*_flush_icache_range)(unsigned long start, unsigned long end); +extern void (*_flush_icache_page)(struct vm_area_struct *vma, + struct page *page); #define flush_dcache_page(page) do { } while (0) #define flush_cache_all() _flush_cache_all() +#define __flush_cache_all() ___flush_cache_all() #define flush_cache_mm(mm) _flush_cache_mm(mm) #define flush_cache_range(mm,start,end) _flush_cache_range(mm,start,end) #define flush_cache_page(vma,page) _flush_cache_page(vma, page) #define flush_cache_sigtramp(addr) _flush_cache_sigtramp(addr) #define flush_page_to_ram(page) _flush_page_to_ram(page) -#define flush_icache_range(start, end) flush_cache_all() - -#define flush_icache_page(vma, page) \ -do { \ - unsigned long addr; \ - addr = (unsigned long) page_address(page); \ - _flush_cache_page(vma, addr); \ -} while (0) +#define flush_icache_range(start, end) _flush_icache_range(start,end) +#define flush_icache_page(vma, page) _flush_icache_page(vma, page) /* @@ -59,6 +59,16 @@ do { \ extern void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long entryhi, unsigned long pagemask); +/* + * - add_temporary_entry() add a temporary TLB entry. We use TLB entries + * starting at the top and working down. This is for populating the + * TLB before trap_init() puts the TLB miss handler in place. It + * should be used only for entries matching the actual page tables, + * to prevent inconsistencies. + */ +extern int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, + unsigned long entryhi, unsigned long pagemask); + /* Basically we have the same two-level (which is the logical three level * Linux page table layout folded) page tables as the i386. Some day @@ -130,13 +140,25 @@ extern void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, #define _CACHE_CACHABLE_NONCOHERENT 0 #else - #define _PAGE_R4KBUG (1<<5) /* workaround for r4k bug */ #define _PAGE_GLOBAL (1<<6) #define _PAGE_VALID (1<<7) #define _PAGE_SILENT_READ (1<<7) /* synonym */ #define _PAGE_DIRTY (1<<8) /* The MIPS dirty bit */ #define _PAGE_SILENT_WRITE (1<<8) +#define _CACHE_MASK (7<<9) + +#if defined(CONFIG_CPU_SB1) + +/* No penalty for being coherent on the SB1, so just + use it for "noncoherent" spaces, too. Shouldn't hurt. */ + +#define _CACHE_UNCACHED (2<<9) +#define _CACHE_CACHABLE_COW (5<<9) +#define _CACHE_CACHABLE_NONCOHERENT (5<<9) + +#else + #define _CACHE_CACHABLE_NO_WA (0<<9) /* R4600 only */ #define _CACHE_CACHABLE_WA (1<<9) /* R4600 only */ #define _CACHE_UNCACHED (2<<9) /* R4[0246]00 */ @@ -145,26 +167,36 @@ extern void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, #define _CACHE_CACHABLE_COW (5<<9) /* R4[04]00 only */ #define _CACHE_CACHABLE_CUW (6<<9) /* R4[04]00 only */ #define _CACHE_CACHABLE_ACCELERATED (7<<9) /* R10000 only */ -#define _CACHE_MASK (7<<9) #endif +#endif #define __READABLE (_PAGE_READ | _PAGE_SILENT_READ | _PAGE_ACCESSED) #define __WRITEABLE (_PAGE_WRITE | _PAGE_SILENT_WRITE | _PAGE_MODIFIED) #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED | _CACHE_MASK) +#ifdef CONFIG_MIPS_UNCACHED +#define PAGE_CACHABLE_DEFAULT _CACHE_UNCACHED +#else +#ifdef CONFIG_CPU_SB1 +#define PAGE_CACHABLE_DEFAULT _CACHE_CACHABLE_COW +#else +#define PAGE_CACHABLE_DEFAULT _CACHE_CACHABLE_NONCOHERENT +#endif +#endif + #define PAGE_NONE __pgprot(_PAGE_PRESENT | _CACHE_CACHABLE_NONCOHERENT) #define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ - _CACHE_CACHABLE_NONCOHERENT) + PAGE_CACHABLE_DEFAULT) #define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_READ | \ - _CACHE_CACHABLE_NONCOHERENT) + PAGE_CACHABLE_DEFAULT) #define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_READ | \ - _CACHE_CACHABLE_NONCOHERENT) + PAGE_CACHABLE_DEFAULT) #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ - _CACHE_CACHABLE_NONCOHERENT) + PAGE_CACHABLE_DEFAULT) #define PAGE_USERIO __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ - _CACHE_UNCACHED) + PAGE_CACHABLE_DEFAULT) #define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ _CACHE_UNCACHED) @@ -200,21 +232,9 @@ extern void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, #define pgd_ERROR(e) \ printk("%s:%d: bad pgd %016lx.\n", __FILE__, __LINE__, pgd_val(e)) -/* - * BAD_PAGETABLE is used when we need a bogus page-table, while - * BAD_PAGE is used for a bogus page. - * - * ZERO_PAGE is a global shared page that is always zero: used - * for zero-mapped memory areas etc.. - */ -extern pte_t __bad_page(void); -extern pte_t *__bad_pagetable(void); - extern unsigned long empty_zero_page; extern unsigned long zero_page_mask; -#define BAD_PAGETABLE __bad_pagetable() -#define BAD_PAGE __bad_page() #define ZERO_PAGE(vaddr) \ (virt_to_page(empty_zero_page + (((unsigned long)(vaddr)) & zero_page_mask))) @@ -269,6 +289,13 @@ extern inline void pte_clear(pte_t *ptep) } /* + * (pmds are folded into pgds so this doesnt get actually called, + * but the define is needed for a generic inline function.) + */ +#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) +#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval) + +/* * Empty pgd/pmd entries point to the invalid_pte_table. */ extern inline int pmd_none(pmd_t pmd) @@ -284,7 +311,7 @@ extern inline int pmd_bad(pmd_t pmd) extern inline int pmd_present(pmd_t pmd) { - return pmd_val(pmd); + return (pmd_val(pmd) != (unsigned long) invalid_pte_table); } extern inline void pmd_clear(pmd_t *pmdp) @@ -303,7 +330,7 @@ extern inline int pgd_present(pgd_t pgd) { return 1; } extern inline void pgd_clear(pgd_t *pgdp) { } /* - * Permanent address of a page. On MIPS64 we never have highmem, so this + * Permanent address of a page. On MIPS we never have highmem, so this * is simple. */ #define page_address(page) ((page)->virtual) @@ -390,7 +417,7 @@ extern inline pte_t pte_mkyoung(pte_t pte) extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) { - return __pte(((physpage & PAGE_MASK) - PAGE_OFFSET) | pgprot_val(pgprot)); + return __pte(physpage | pgprot_val(pgprot)); } extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) @@ -424,19 +451,6 @@ extern inline pte_t *pte_offset(pmd_t * dir, unsigned long address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); } -/* - * Initialize new page directory with pointers to invalid ptes - */ -extern void pgd_init(unsigned long page); - -extern void __bad_pte(pmd_t *pmd); -extern void __bad_pte_kernel(pmd_t *pmd); - -#define pte_free_kernel(pte) free_pte_fast(pte) -#define pte_free(pte) free_pte_fast(pte) -#define pgd_free(pgd) free_pgd_fast(pgd) -#define pgd_alloc() get_pgd_fast() - extern int do_check_pgt_cache(int, int); extern pgd_t swapper_pg_dir[1024]; @@ -639,6 +653,19 @@ extern inline void set_wired(unsigned long val) : : "r" (val)); } +extern inline unsigned long get_info(void) +{ + unsigned long val; + + __asm__( + ".set push\n\t" + ".set reorder\n\t" + "mfc0 %0, $7\n\t" + ".set pop" + : "=r" (val)); + return val; +} + /* CP0_TAGLO and CP0_TAGHI registers */ extern inline unsigned long get_taglo(void) { diff --git a/include/asm-mips/pmc/ev64120.h b/include/asm-mips/pmc/ev64120.h new file mode 100644 index 000000000000..74ad8c5105e3 --- /dev/null +++ b/include/asm-mips/pmc/ev64120.h @@ -0,0 +1,59 @@ +/* + * This is a direct copy of the ev96100.h file, with a global search and + * replace. The numbers are the same. + * + * The reason I'm duplicating this is so that the 64120/96100 + * defines won't be confusing in the source code. + */ +#ifndef _ASM_PMC_CP7000_H +#define _ASM_PMC_CP7000_H + +#include <asm/addrspace.h> + +/* + * GT64120 config space base address + */ +#define GT64120_BASE (KSEG1ADDR(0x14000000)) +#define MIPS_GT_BASE GT64120_BASE + +/* + * PCI Bus allocation + */ +#define GT_PCI_MEM_BASE 0x12000000 +#define GT_PCI_MEM_SIZE 0x02000000 +#define GT_PCI_IO_BASE 0x10000000 +#define GT_PCI_IO_SIZE 0x02000000 +#define GT_ISA_IO_BASE PCI_IO_BASE + +/* + * Duart I/O ports. + */ +#define EV64120_COM1_BASE_ADDR (0x1d000000 + 0x20) +#define EV64120_COM2_BASE_ADDR (0x1d000000 + 0x00) + + +/* + * EV64120 interrupt controller register base. + */ +#define EV64120_ICTRL_REGS_BASE (KSEG1ADDR(0x1f000000)) + +/* + * EV64120 UART register base. + */ +#define EV64120_UART0_REGS_BASE (KSEG1ADDR(EV64120_COM1_BASE_ADDR)) +#define EV64120_UART1_REGS_BASE (KSEG1ADDR(EV64120_COM2_BASE_ADDR)) +#define EV64120_BASE_BAUD ( 3686400 / 16 ) + + +/* + * Because of an error/peculiarity in the Galileo chip, we need to swap the + * bytes when running bigendian. + */ + +#define GT_WRITE(ofs, data) \ + *(volatile u32 *)(MIPS_GT_BASE+ofs) = cpu_to_le32(data) +#define GT_READ(ofs, data) \ + *data = le32_to_cpu(*(volatile u32 *)(MIPS_GT_BASE+ofs)) + + +#endif /* _ASM_PMC_CP7000_H */ diff --git a/include/asm-mips/pmc/ev64120int.h b/include/asm-mips/pmc/ev64120int.h new file mode 100644 index 000000000000..463f6b39dcaf --- /dev/null +++ b/include/asm-mips/pmc/ev64120int.h @@ -0,0 +1,32 @@ +#ifndef _ASM_PMC_CP7000INT_H +#define _ASM_PMC_CP7000INT_H + +#define INT_CAUSE_MAIN 0 +#define INT_CAUSE_HIGH 1 + +#define MAX_CAUSE_REGS 4 +#define MAX_CAUSE_REG_WIDTH 32 + +void hook_irq_handler (int int_cause , int bit_num , void *isr_ptr); +int disable_galileo_irq (int int_cause , int bit_num); +int enable_galileo_irq (int int_cause , int bit_num); + +extern struct tq_struct irq_handlers[MAX_CAUSE_REGS][MAX_CAUSE_REG_WIDTH]; + +/* + * PCI interrupts will come in on either the INTA or INTD interrups lines, + * which are mapped to the #2 and #5 interrupt pins of the MIPS. On our + * boards, they all either come in on IntD or they all come in on IntA, they + * aren't mixed. There can be numerous PCI interrupts, so we keep a list of the + * "requested" interrupt numbers and go through the list whenever we get an + * IntA/D. + * + * All PCI interrupts have numbers >= 20 by arbitrary convention. Any + * interrupt < 8 is an interrupt that is maskable on MIPS. + */ + +#define TIMER 4 +#define INTA 2 +#define INTD 5 + +#endif /* _ASM_PMC_CP7000INT_H */ diff --git a/include/asm-mips/processor.h b/include/asm-mips/processor.h index decd449f39a8..b0273cca1735 100644 --- a/include/asm-mips/processor.h +++ b/include/asm-mips/processor.h @@ -1,11 +1,10 @@ -/* $Id: processor.h,v 1.25 2000/02/05 06:47:37 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1994 Waldorf GMBH - * Copyright (C) 1995, 1996, 1997, 1998 Ralf Baechle + * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001 Ralf Baechle * Copyright (C) 1996 Paul M. Antoine * Copyright (C) 1999 Silicon Graphics, Inc. */ @@ -30,6 +29,7 @@ #include <asm/system.h> struct mips_cpuinfo { + unsigned long udelay_val; unsigned long *pgd_quick; unsigned long *pte_quick; unsigned long pgtable_cache_sz; @@ -44,7 +44,6 @@ extern void r3081_wait(void); extern void r4k_wait(void); extern char cyclecounter_available; /* only available from R4000 upwards. */ extern char dedicated_iv_available; /* some embedded MIPS like Nevada */ -extern char vce_available; /* Supports VCED / VCEI exceptions */ extern struct mips_cpuinfo boot_cpu_data; extern unsigned int vced_count, vcei_count; @@ -83,7 +82,7 @@ extern struct task_struct *last_task_used_math; * for a 64 bit kernel expandable to 8192EB, of which the current MIPS * implementations will "only" be able to use 1TB ... */ -#define TASK_SIZE (0x80000000UL) +#define TASK_SIZE (0x7fff8000UL) /* This decides where the kernel will search for a free chunk of vm * space during mmap's. diff --git a/include/asm-mips/ptrace.h b/include/asm-mips/ptrace.h index b395fe1be56a..39ac6cea4c49 100644 --- a/include/asm-mips/ptrace.h +++ b/include/asm-mips/ptrace.h @@ -1,16 +1,15 @@ -/* $Id: ptrace.h,v 1.7 1999/09/28 22:27:17 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1994, 1995, 1996, 1997, 1998 by Ralf Baechle + * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000 by Ralf Baechle * * Machine dependent structs and defines to help the user use * the ptrace system call. */ -#ifndef __ASM_MIPS_PTRACE_H -#define __ASM_MIPS_PTRACE_H +#ifndef _ASM_PTRACE_H +#define _ASM_PTRACE_H #include <asm/isadep.h> #include <linux/types.h> @@ -52,6 +51,19 @@ struct pt_regs { #endif /* !(_LANGUAGE_ASSEMBLY) */ +/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ +/* #define PTRACE_GETREGS 12 */ +/* #define PTRACE_SETREGS 13 */ +/* #define PTRACE_GETFPREGS 14 */ +/* #define PTRACE_SETFPREGS 15 */ +/* #define PTRACE_GETFPXREGS 18 */ +/* #define PTRACE_SETFPXREGS 19 */ + +#define PTRACE_SETOPTIONS 21 + +/* options set using PTRACE_SETOPTIONS */ +#define PTRACE_O_TRACESYSGOOD 0x00000001 + #ifdef _LANGUAGE_ASSEMBLY #include <asm/offset.h> #endif @@ -71,4 +83,4 @@ extern void show_regs(struct pt_regs *); #endif -#endif /* __ASM_MIPS_PTRACE_H */ +#endif /* _ASM_PTRACE_H */ diff --git a/include/asm-mips/resource.h b/include/asm-mips/resource.h index 718e983e61f2..286b71b7057e 100644 --- a/include/asm-mips/resource.h +++ b/include/asm-mips/resource.h @@ -1,10 +1,9 @@ -/* $Id: resource.h,v 1.4 2000/01/27 23:45:30 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1995, 1996, 1998 by Ralf Baechle + * Copyright (C) 1995, 96, 98, 2000 by Ralf Baechle */ #ifndef _ASM_RESOURCE_H #define _ASM_RESOURCE_H @@ -26,14 +25,14 @@ #define RLIM_NLIMITS 11 /* Number of limit flavors. */ +#ifdef __KERNEL__ + /* * SuS says limits have to be unsigned. * Which makes a ton more sense anyway. */ #define RLIM_INFINITY 0x7fffffffUL -#ifdef __KERNEL__ - #define INIT_RLIMITS \ { \ { RLIM_INFINITY, RLIM_INFINITY }, \ diff --git a/include/asm-mips/riscos-syscall.h b/include/asm-mips/riscos-syscall.h new file mode 100644 index 000000000000..8cb87df377bb --- /dev/null +++ b/include/asm-mips/riscos-syscall.h @@ -0,0 +1,979 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 96, 97, 98, 99, 2000 by Ralf Baechle + */ +#ifndef _ASM_RISCOS_SYSCALL_H +#define _ASM_RISCOS_SYSCALL_H + +/* + * The syscalls 0 - 3999 are reserved for a down to the root syscall + * compatibility with RISC/os and IRIX. We'll see how to deal with the + * various "real" BSD variants like Ultrix, NetBSD ... + */ + +/* + * SVR4 syscalls are in the range from 1 to 999 + */ +#define __NR_SVR4 0 +#define __NR_SVR4_syscall (__NR_SVR4 + 0) +#define __NR_SVR4_exit (__NR_SVR4 + 1) +#define __NR_SVR4_fork (__NR_SVR4 + 2) +#define __NR_SVR4_read (__NR_SVR4 + 3) +#define __NR_SVR4_write (__NR_SVR4 + 4) +#define __NR_SVR4_open (__NR_SVR4 + 5) +#define __NR_SVR4_close (__NR_SVR4 + 6) +#define __NR_SVR4_wait (__NR_SVR4 + 7) +#define __NR_SVR4_creat (__NR_SVR4 + 8) +#define __NR_SVR4_link (__NR_SVR4 + 9) +#define __NR_SVR4_unlink (__NR_SVR4 + 10) +#define __NR_SVR4_exec (__NR_SVR4 + 11) +#define __NR_SVR4_chdir (__NR_SVR4 + 12) +#define __NR_SVR4_gtime (__NR_SVR4 + 13) +#define __NR_SVR4_mknod (__NR_SVR4 + 14) +#define __NR_SVR4_chmod (__NR_SVR4 + 15) +#define __NR_SVR4_chown (__NR_SVR4 + 16) +#define __NR_SVR4_sbreak (__NR_SVR4 + 17) +#define __NR_SVR4_stat (__NR_SVR4 + 18) +#define __NR_SVR4_lseek (__NR_SVR4 + 19) +#define __NR_SVR4_getpid (__NR_SVR4 + 20) +#define __NR_SVR4_mount (__NR_SVR4 + 21) +#define __NR_SVR4_umount (__NR_SVR4 + 22) +#define __NR_SVR4_setuid (__NR_SVR4 + 23) +#define __NR_SVR4_getuid (__NR_SVR4 + 24) +#define __NR_SVR4_stime (__NR_SVR4 + 25) +#define __NR_SVR4_ptrace (__NR_SVR4 + 26) +#define __NR_SVR4_alarm (__NR_SVR4 + 27) +#define __NR_SVR4_fstat (__NR_SVR4 + 28) +#define __NR_SVR4_pause (__NR_SVR4 + 29) +#define __NR_SVR4_utime (__NR_SVR4 + 30) +#define __NR_SVR4_stty (__NR_SVR4 + 31) +#define __NR_SVR4_gtty (__NR_SVR4 + 32) +#define __NR_SVR4_access (__NR_SVR4 + 33) +#define __NR_SVR4_nice (__NR_SVR4 + 34) +#define __NR_SVR4_statfs (__NR_SVR4 + 35) +#define __NR_SVR4_sync (__NR_SVR4 + 36) +#define __NR_SVR4_kill (__NR_SVR4 + 37) +#define __NR_SVR4_fstatfs (__NR_SVR4 + 38) +#define __NR_SVR4_setpgrp (__NR_SVR4 + 39) +#define __NR_SVR4_cxenix (__NR_SVR4 + 40) +#define __NR_SVR4_dup (__NR_SVR4 + 41) +#define __NR_SVR4_pipe (__NR_SVR4 + 42) +#define __NR_SVR4_times (__NR_SVR4 + 43) +#define __NR_SVR4_profil (__NR_SVR4 + 44) +#define __NR_SVR4_plock (__NR_SVR4 + 45) +#define __NR_SVR4_setgid (__NR_SVR4 + 46) +#define __NR_SVR4_getgid (__NR_SVR4 + 47) +#define __NR_SVR4_sig (__NR_SVR4 + 48) +#define __NR_SVR4_msgsys (__NR_SVR4 + 49) +#define __NR_SVR4_sysmips (__NR_SVR4 + 50) +#define __NR_SVR4_sysacct (__NR_SVR4 + 51) +#define __NR_SVR4_shmsys (__NR_SVR4 + 52) +#define __NR_SVR4_semsys (__NR_SVR4 + 53) +#define __NR_SVR4_ioctl (__NR_SVR4 + 54) +#define __NR_SVR4_uadmin (__NR_SVR4 + 55) +#define __NR_SVR4_exch (__NR_SVR4 + 56) +#define __NR_SVR4_utssys (__NR_SVR4 + 57) +#define __NR_SVR4_fsync (__NR_SVR4 + 58) +#define __NR_SVR4_exece (__NR_SVR4 + 59) +#define __NR_SVR4_umask (__NR_SVR4 + 60) +#define __NR_SVR4_chroot (__NR_SVR4 + 61) +#define __NR_SVR4_fcntl (__NR_SVR4 + 62) +#define __NR_SVR4_ulimit (__NR_SVR4 + 63) +#define __NR_SVR4_reserved1 (__NR_SVR4 + 64) +#define __NR_SVR4_reserved2 (__NR_SVR4 + 65) +#define __NR_SVR4_reserved3 (__NR_SVR4 + 66) +#define __NR_SVR4_reserved4 (__NR_SVR4 + 67) +#define __NR_SVR4_reserved5 (__NR_SVR4 + 68) +#define __NR_SVR4_reserved6 (__NR_SVR4 + 69) +#define __NR_SVR4_advfs (__NR_SVR4 + 70) +#define __NR_SVR4_unadvfs (__NR_SVR4 + 71) +#define __NR_SVR4_unused1 (__NR_SVR4 + 72) +#define __NR_SVR4_unused2 (__NR_SVR4 + 73) +#define __NR_SVR4_rfstart (__NR_SVR4 + 74) +#define __NR_SVR4_unused3 (__NR_SVR4 + 75) +#define __NR_SVR4_rdebug (__NR_SVR4 + 76) +#define __NR_SVR4_rfstop (__NR_SVR4 + 77) +#define __NR_SVR4_rfsys (__NR_SVR4 + 78) +#define __NR_SVR4_rmdir (__NR_SVR4 + 79) +#define __NR_SVR4_mkdir (__NR_SVR4 + 80) +#define __NR_SVR4_getdents (__NR_SVR4 + 81) +#define __NR_SVR4_libattach (__NR_SVR4 + 82) +#define __NR_SVR4_libdetach (__NR_SVR4 + 83) +#define __NR_SVR4_sysfs (__NR_SVR4 + 84) +#define __NR_SVR4_getmsg (__NR_SVR4 + 85) +#define __NR_SVR4_putmsg (__NR_SVR4 + 86) +#define __NR_SVR4_poll (__NR_SVR4 + 87) +#define __NR_SVR4_lstat (__NR_SVR4 + 88) +#define __NR_SVR4_symlink (__NR_SVR4 + 89) +#define __NR_SVR4_readlink (__NR_SVR4 + 90) +#define __NR_SVR4_setgroups (__NR_SVR4 + 91) +#define __NR_SVR4_getgroups (__NR_SVR4 + 92) +#define __NR_SVR4_fchmod (__NR_SVR4 + 93) +#define __NR_SVR4_fchown (__NR_SVR4 + 94) +#define __NR_SVR4_sigprocmask (__NR_SVR4 + 95) +#define __NR_SVR4_sigsuspend (__NR_SVR4 + 96) +#define __NR_SVR4_sigaltstack (__NR_SVR4 + 97) +#define __NR_SVR4_sigaction (__NR_SVR4 + 98) +#define __NR_SVR4_sigpending (__NR_SVR4 + 99) +#define __NR_SVR4_setcontext (__NR_SVR4 + 100) +#define __NR_SVR4_evsys (__NR_SVR4 + 101) +#define __NR_SVR4_evtrapret (__NR_SVR4 + 102) +#define __NR_SVR4_statvfs (__NR_SVR4 + 103) +#define __NR_SVR4_fstatvfs (__NR_SVR4 + 104) +#define __NR_SVR4_reserved7 (__NR_SVR4 + 105) +#define __NR_SVR4_nfssys (__NR_SVR4 + 106) +#define __NR_SVR4_waitid (__NR_SVR4 + 107) +#define __NR_SVR4_sigsendset (__NR_SVR4 + 108) +#define __NR_SVR4_hrtsys (__NR_SVR4 + 109) +#define __NR_SVR4_acancel (__NR_SVR4 + 110) +#define __NR_SVR4_async (__NR_SVR4 + 111) +#define __NR_SVR4_priocntlset (__NR_SVR4 + 112) +#define __NR_SVR4_pathconf (__NR_SVR4 + 113) +#define __NR_SVR4_mincore (__NR_SVR4 + 114) +#define __NR_SVR4_mmap (__NR_SVR4 + 115) +#define __NR_SVR4_mprotect (__NR_SVR4 + 116) +#define __NR_SVR4_munmap (__NR_SVR4 + 117) +#define __NR_SVR4_fpathconf (__NR_SVR4 + 118) +#define __NR_SVR4_vfork (__NR_SVR4 + 119) +#define __NR_SVR4_fchdir (__NR_SVR4 + 120) +#define __NR_SVR4_readv (__NR_SVR4 + 121) +#define __NR_SVR4_writev (__NR_SVR4 + 122) +#define __NR_SVR4_xstat (__NR_SVR4 + 123) +#define __NR_SVR4_lxstat (__NR_SVR4 + 124) +#define __NR_SVR4_fxstat (__NR_SVR4 + 125) +#define __NR_SVR4_xmknod (__NR_SVR4 + 126) +#define __NR_SVR4_clocal (__NR_SVR4 + 127) +#define __NR_SVR4_setrlimit (__NR_SVR4 + 128) +#define __NR_SVR4_getrlimit (__NR_SVR4 + 129) +#define __NR_SVR4_lchown (__NR_SVR4 + 130) +#define __NR_SVR4_memcntl (__NR_SVR4 + 131) +#define __NR_SVR4_getpmsg (__NR_SVR4 + 132) +#define __NR_SVR4_putpmsg (__NR_SVR4 + 133) +#define __NR_SVR4_rename (__NR_SVR4 + 134) +#define __NR_SVR4_nuname (__NR_SVR4 + 135) +#define __NR_SVR4_setegid (__NR_SVR4 + 136) +#define __NR_SVR4_sysconf (__NR_SVR4 + 137) +#define __NR_SVR4_adjtime (__NR_SVR4 + 138) +#define __NR_SVR4_sysinfo (__NR_SVR4 + 139) +#define __NR_SVR4_reserved8 (__NR_SVR4 + 140) +#define __NR_SVR4_seteuid (__NR_SVR4 + 141) +#define __NR_SVR4_PYRAMID_statis (__NR_SVR4 + 142) +#define __NR_SVR4_PYRAMID_tuning (__NR_SVR4 + 143) +#define __NR_SVR4_PYRAMID_forcerr (__NR_SVR4 + 144) +#define __NR_SVR4_PYRAMID_mpcntl (__NR_SVR4 + 145) +#define __NR_SVR4_reserved9 (__NR_SVR4 + 146) +#define __NR_SVR4_reserved10 (__NR_SVR4 + 147) +#define __NR_SVR4_reserved11 (__NR_SVR4 + 148) +#define __NR_SVR4_reserved12 (__NR_SVR4 + 149) +#define __NR_SVR4_reserved13 (__NR_SVR4 + 150) +#define __NR_SVR4_reserved14 (__NR_SVR4 + 151) +#define __NR_SVR4_reserved15 (__NR_SVR4 + 152) +#define __NR_SVR4_reserved16 (__NR_SVR4 + 153) +#define __NR_SVR4_reserved17 (__NR_SVR4 + 154) +#define __NR_SVR4_reserved18 (__NR_SVR4 + 155) +#define __NR_SVR4_reserved19 (__NR_SVR4 + 156) +#define __NR_SVR4_reserved20 (__NR_SVR4 + 157) +#define __NR_SVR4_reserved21 (__NR_SVR4 + 158) +#define __NR_SVR4_reserved22 (__NR_SVR4 + 159) +#define __NR_SVR4_reserved23 (__NR_SVR4 + 160) +#define __NR_SVR4_reserved24 (__NR_SVR4 + 161) +#define __NR_SVR4_reserved25 (__NR_SVR4 + 162) +#define __NR_SVR4_reserved26 (__NR_SVR4 + 163) +#define __NR_SVR4_reserved27 (__NR_SVR4 + 164) +#define __NR_SVR4_reserved28 (__NR_SVR4 + 165) +#define __NR_SVR4_reserved29 (__NR_SVR4 + 166) +#define __NR_SVR4_reserved30 (__NR_SVR4 + 167) +#define __NR_SVR4_reserved31 (__NR_SVR4 + 168) +#define __NR_SVR4_reserved32 (__NR_SVR4 + 169) +#define __NR_SVR4_reserved33 (__NR_SVR4 + 170) +#define __NR_SVR4_reserved34 (__NR_SVR4 + 171) +#define __NR_SVR4_reserved35 (__NR_SVR4 + 172) +#define __NR_SVR4_reserved36 (__NR_SVR4 + 173) +#define __NR_SVR4_reserved37 (__NR_SVR4 + 174) +#define __NR_SVR4_reserved38 (__NR_SVR4 + 175) +#define __NR_SVR4_reserved39 (__NR_SVR4 + 176) +#define __NR_SVR4_reserved40 (__NR_SVR4 + 177) +#define __NR_SVR4_reserved41 (__NR_SVR4 + 178) +#define __NR_SVR4_reserved42 (__NR_SVR4 + 179) +#define __NR_SVR4_reserved43 (__NR_SVR4 + 180) +#define __NR_SVR4_reserved44 (__NR_SVR4 + 181) +#define __NR_SVR4_reserved45 (__NR_SVR4 + 182) +#define __NR_SVR4_reserved46 (__NR_SVR4 + 183) +#define __NR_SVR4_reserved47 (__NR_SVR4 + 184) +#define __NR_SVR4_reserved48 (__NR_SVR4 + 185) +#define __NR_SVR4_reserved49 (__NR_SVR4 + 186) +#define __NR_SVR4_reserved50 (__NR_SVR4 + 187) +#define __NR_SVR4_reserved51 (__NR_SVR4 + 188) +#define __NR_SVR4_reserved52 (__NR_SVR4 + 189) +#define __NR_SVR4_reserved53 (__NR_SVR4 + 190) +#define __NR_SVR4_reserved54 (__NR_SVR4 + 191) +#define __NR_SVR4_reserved55 (__NR_SVR4 + 192) +#define __NR_SVR4_reserved56 (__NR_SVR4 + 193) +#define __NR_SVR4_reserved57 (__NR_SVR4 + 194) +#define __NR_SVR4_reserved58 (__NR_SVR4 + 195) +#define __NR_SVR4_reserved59 (__NR_SVR4 + 196) +#define __NR_SVR4_reserved60 (__NR_SVR4 + 197) +#define __NR_SVR4_reserved61 (__NR_SVR4 + 198) +#define __NR_SVR4_reserved62 (__NR_SVR4 + 199) +#define __NR_SVR4_reserved63 (__NR_SVR4 + 200) +#define __NR_SVR4_aread (__NR_SVR4 + 201) +#define __NR_SVR4_awrite (__NR_SVR4 + 202) +#define __NR_SVR4_listio (__NR_SVR4 + 203) +#define __NR_SVR4_mips_acancel (__NR_SVR4 + 204) +#define __NR_SVR4_astatus (__NR_SVR4 + 205) +#define __NR_SVR4_await (__NR_SVR4 + 206) +#define __NR_SVR4_areadv (__NR_SVR4 + 207) +#define __NR_SVR4_awritev (__NR_SVR4 + 208) +#define __NR_SVR4_MIPS_reserved1 (__NR_SVR4 + 209) +#define __NR_SVR4_MIPS_reserved2 (__NR_SVR4 + 210) +#define __NR_SVR4_MIPS_reserved3 (__NR_SVR4 + 211) +#define __NR_SVR4_MIPS_reserved4 (__NR_SVR4 + 212) +#define __NR_SVR4_MIPS_reserved5 (__NR_SVR4 + 213) +#define __NR_SVR4_MIPS_reserved6 (__NR_SVR4 + 214) +#define __NR_SVR4_MIPS_reserved7 (__NR_SVR4 + 215) +#define __NR_SVR4_MIPS_reserved8 (__NR_SVR4 + 216) +#define __NR_SVR4_MIPS_reserved9 (__NR_SVR4 + 217) +#define __NR_SVR4_MIPS_reserved10 (__NR_SVR4 + 218) +#define __NR_SVR4_MIPS_reserved11 (__NR_SVR4 + 219) +#define __NR_SVR4_MIPS_reserved12 (__NR_SVR4 + 220) +#define __NR_SVR4_CDC_reserved1 (__NR_SVR4 + 221) +#define __NR_SVR4_CDC_reserved2 (__NR_SVR4 + 222) +#define __NR_SVR4_CDC_reserved3 (__NR_SVR4 + 223) +#define __NR_SVR4_CDC_reserved4 (__NR_SVR4 + 224) +#define __NR_SVR4_CDC_reserved5 (__NR_SVR4 + 225) +#define __NR_SVR4_CDC_reserved6 (__NR_SVR4 + 226) +#define __NR_SVR4_CDC_reserved7 (__NR_SVR4 + 227) +#define __NR_SVR4_CDC_reserved8 (__NR_SVR4 + 228) +#define __NR_SVR4_CDC_reserved9 (__NR_SVR4 + 229) +#define __NR_SVR4_CDC_reserved10 (__NR_SVR4 + 230) +#define __NR_SVR4_CDC_reserved11 (__NR_SVR4 + 231) +#define __NR_SVR4_CDC_reserved12 (__NR_SVR4 + 232) +#define __NR_SVR4_CDC_reserved13 (__NR_SVR4 + 233) +#define __NR_SVR4_CDC_reserved14 (__NR_SVR4 + 234) +#define __NR_SVR4_CDC_reserved15 (__NR_SVR4 + 235) +#define __NR_SVR4_CDC_reserved16 (__NR_SVR4 + 236) +#define __NR_SVR4_CDC_reserved17 (__NR_SVR4 + 237) +#define __NR_SVR4_CDC_reserved18 (__NR_SVR4 + 238) +#define __NR_SVR4_CDC_reserved19 (__NR_SVR4 + 239) +#define __NR_SVR4_CDC_reserved20 (__NR_SVR4 + 240) + +/* + * SYS V syscalls are in the range from 1000 to 1999 + */ +#define __NR_SYSV 1000 +#define __NR_SYSV_syscall (__NR_SYSV + 0) +#define __NR_SYSV_exit (__NR_SYSV + 1) +#define __NR_SYSV_fork (__NR_SYSV + 2) +#define __NR_SYSV_read (__NR_SYSV + 3) +#define __NR_SYSV_write (__NR_SYSV + 4) +#define __NR_SYSV_open (__NR_SYSV + 5) +#define __NR_SYSV_close (__NR_SYSV + 6) +#define __NR_SYSV_wait (__NR_SYSV + 7) +#define __NR_SYSV_creat (__NR_SYSV + 8) +#define __NR_SYSV_link (__NR_SYSV + 9) +#define __NR_SYSV_unlink (__NR_SYSV + 10) +#define __NR_SYSV_execv (__NR_SYSV + 11) +#define __NR_SYSV_chdir (__NR_SYSV + 12) +#define __NR_SYSV_time (__NR_SYSV + 13) +#define __NR_SYSV_mknod (__NR_SYSV + 14) +#define __NR_SYSV_chmod (__NR_SYSV + 15) +#define __NR_SYSV_chown (__NR_SYSV + 16) +#define __NR_SYSV_brk (__NR_SYSV + 17) +#define __NR_SYSV_stat (__NR_SYSV + 18) +#define __NR_SYSV_lseek (__NR_SYSV + 19) +#define __NR_SYSV_getpid (__NR_SYSV + 20) +#define __NR_SYSV_mount (__NR_SYSV + 21) +#define __NR_SYSV_umount (__NR_SYSV + 22) +#define __NR_SYSV_setuid (__NR_SYSV + 23) +#define __NR_SYSV_getuid (__NR_SYSV + 24) +#define __NR_SYSV_stime (__NR_SYSV + 25) +#define __NR_SYSV_ptrace (__NR_SYSV + 26) +#define __NR_SYSV_alarm (__NR_SYSV + 27) +#define __NR_SYSV_fstat (__NR_SYSV + 28) +#define __NR_SYSV_pause (__NR_SYSV + 29) +#define __NR_SYSV_utime (__NR_SYSV + 30) +#define __NR_SYSV_stty (__NR_SYSV + 31) +#define __NR_SYSV_gtty (__NR_SYSV + 32) +#define __NR_SYSV_access (__NR_SYSV + 33) +#define __NR_SYSV_nice (__NR_SYSV + 34) +#define __NR_SYSV_statfs (__NR_SYSV + 35) +#define __NR_SYSV_sync (__NR_SYSV + 36) +#define __NR_SYSV_kill (__NR_SYSV + 37) +#define __NR_SYSV_fstatfs (__NR_SYSV + 38) +#define __NR_SYSV_setpgrp (__NR_SYSV + 39) +#define __NR_SYSV_syssgi (__NR_SYSV + 40) +#define __NR_SYSV_dup (__NR_SYSV + 41) +#define __NR_SYSV_pipe (__NR_SYSV + 42) +#define __NR_SYSV_times (__NR_SYSV + 43) +#define __NR_SYSV_profil (__NR_SYSV + 44) +#define __NR_SYSV_plock (__NR_SYSV + 45) +#define __NR_SYSV_setgid (__NR_SYSV + 46) +#define __NR_SYSV_getgid (__NR_SYSV + 47) +#define __NR_SYSV_sig (__NR_SYSV + 48) +#define __NR_SYSV_msgsys (__NR_SYSV + 49) +#define __NR_SYSV_sysmips (__NR_SYSV + 50) +#define __NR_SYSV_acct (__NR_SYSV + 51) +#define __NR_SYSV_shmsys (__NR_SYSV + 52) +#define __NR_SYSV_semsys (__NR_SYSV + 53) +#define __NR_SYSV_ioctl (__NR_SYSV + 54) +#define __NR_SYSV_uadmin (__NR_SYSV + 55) +#define __NR_SYSV_sysmp (__NR_SYSV + 56) +#define __NR_SYSV_utssys (__NR_SYSV + 57) +#define __NR_SYSV_USG_reserved1 (__NR_SYSV + 58) +#define __NR_SYSV_execve (__NR_SYSV + 59) +#define __NR_SYSV_umask (__NR_SYSV + 60) +#define __NR_SYSV_chroot (__NR_SYSV + 61) +#define __NR_SYSV_fcntl (__NR_SYSV + 62) +#define __NR_SYSV_ulimit (__NR_SYSV + 63) +#define __NR_SYSV_SAFARI4_reserved1 (__NR_SYSV + 64) +#define __NR_SYSV_SAFARI4_reserved2 (__NR_SYSV + 65) +#define __NR_SYSV_SAFARI4_reserved3 (__NR_SYSV + 66) +#define __NR_SYSV_SAFARI4_reserved4 (__NR_SYSV + 67) +#define __NR_SYSV_SAFARI4_reserved5 (__NR_SYSV + 68) +#define __NR_SYSV_SAFARI4_reserved6 (__NR_SYSV + 69) +#define __NR_SYSV_advfs (__NR_SYSV + 70) +#define __NR_SYSV_unadvfs (__NR_SYSV + 71) +#define __NR_SYSV_rmount (__NR_SYSV + 72) +#define __NR_SYSV_rumount (__NR_SYSV + 73) +#define __NR_SYSV_rfstart (__NR_SYSV + 74) +#define __NR_SYSV_getrlimit64 (__NR_SYSV + 75) +#define __NR_SYSV_setrlimit64 (__NR_SYSV + 76) +#define __NR_SYSV_nanosleep (__NR_SYSV + 77) +#define __NR_SYSV_lseek64 (__NR_SYSV + 78) +#define __NR_SYSV_rmdir (__NR_SYSV + 79) +#define __NR_SYSV_mkdir (__NR_SYSV + 80) +#define __NR_SYSV_getdents (__NR_SYSV + 81) +#define __NR_SYSV_sginap (__NR_SYSV + 82) +#define __NR_SYSV_sgikopt (__NR_SYSV + 83) +#define __NR_SYSV_sysfs (__NR_SYSV + 84) +#define __NR_SYSV_getmsg (__NR_SYSV + 85) +#define __NR_SYSV_putmsg (__NR_SYSV + 86) +#define __NR_SYSV_poll (__NR_SYSV + 87) +#define __NR_SYSV_sigreturn (__NR_SYSV + 88) +#define __NR_SYSV_accept (__NR_SYSV + 89) +#define __NR_SYSV_bind (__NR_SYSV + 90) +#define __NR_SYSV_connect (__NR_SYSV + 91) +#define __NR_SYSV_gethostid (__NR_SYSV + 92) +#define __NR_SYSV_getpeername (__NR_SYSV + 93) +#define __NR_SYSV_getsockname (__NR_SYSV + 94) +#define __NR_SYSV_getsockopt (__NR_SYSV + 95) +#define __NR_SYSV_listen (__NR_SYSV + 96) +#define __NR_SYSV_recv (__NR_SYSV + 97) +#define __NR_SYSV_recvfrom (__NR_SYSV + 98) +#define __NR_SYSV_recvmsg (__NR_SYSV + 99) +#define __NR_SYSV_select (__NR_SYSV + 100) +#define __NR_SYSV_send (__NR_SYSV + 101) +#define __NR_SYSV_sendmsg (__NR_SYSV + 102) +#define __NR_SYSV_sendto (__NR_SYSV + 103) +#define __NR_SYSV_sethostid (__NR_SYSV + 104) +#define __NR_SYSV_setsockopt (__NR_SYSV + 105) +#define __NR_SYSV_shutdown (__NR_SYSV + 106) +#define __NR_SYSV_socket (__NR_SYSV + 107) +#define __NR_SYSV_gethostname (__NR_SYSV + 108) +#define __NR_SYSV_sethostname (__NR_SYSV + 109) +#define __NR_SYSV_getdomainname (__NR_SYSV + 110) +#define __NR_SYSV_setdomainname (__NR_SYSV + 111) +#define __NR_SYSV_truncate (__NR_SYSV + 112) +#define __NR_SYSV_ftruncate (__NR_SYSV + 113) +#define __NR_SYSV_rename (__NR_SYSV + 114) +#define __NR_SYSV_symlink (__NR_SYSV + 115) +#define __NR_SYSV_readlink (__NR_SYSV + 116) +#define __NR_SYSV_lstat (__NR_SYSV + 117) +#define __NR_SYSV_nfsmount (__NR_SYSV + 118) +#define __NR_SYSV_nfssvc (__NR_SYSV + 119) +#define __NR_SYSV_getfh (__NR_SYSV + 120) +#define __NR_SYSV_async_daemon (__NR_SYSV + 121) +#define __NR_SYSV_exportfs (__NR_SYSV + 122) +#define __NR_SYSV_setregid (__NR_SYSV + 123) +#define __NR_SYSV_setreuid (__NR_SYSV + 124) +#define __NR_SYSV_getitimer (__NR_SYSV + 125) +#define __NR_SYSV_setitimer (__NR_SYSV + 126) +#define __NR_SYSV_adjtime (__NR_SYSV + 127) +#define __NR_SYSV_BSD_getime (__NR_SYSV + 128) +#define __NR_SYSV_sproc (__NR_SYSV + 129) +#define __NR_SYSV_prctl (__NR_SYSV + 130) +#define __NR_SYSV_procblk (__NR_SYSV + 131) +#define __NR_SYSV_sprocsp (__NR_SYSV + 132) +#define __NR_SYSV_sgigsc (__NR_SYSV + 133) +#define __NR_SYSV_mmap (__NR_SYSV + 134) +#define __NR_SYSV_munmap (__NR_SYSV + 135) +#define __NR_SYSV_mprotect (__NR_SYSV + 136) +#define __NR_SYSV_msync (__NR_SYSV + 137) +#define __NR_SYSV_madvise (__NR_SYSV + 138) +#define __NR_SYSV_pagelock (__NR_SYSV + 139) +#define __NR_SYSV_getpagesize (__NR_SYSV + 140) +#define __NR_SYSV_quotactl (__NR_SYSV + 141) +#define __NR_SYSV_libdetach (__NR_SYSV + 142) +#define __NR_SYSV_BSDgetpgrp (__NR_SYSV + 143) +#define __NR_SYSV_BSDsetpgrp (__NR_SYSV + 144) +#define __NR_SYSV_vhangup (__NR_SYSV + 145) +#define __NR_SYSV_fsync (__NR_SYSV + 146) +#define __NR_SYSV_fchdir (__NR_SYSV + 147) +#define __NR_SYSV_getrlimit (__NR_SYSV + 148) +#define __NR_SYSV_setrlimit (__NR_SYSV + 149) +#define __NR_SYSV_cacheflush (__NR_SYSV + 150) +#define __NR_SYSV_cachectl (__NR_SYSV + 151) +#define __NR_SYSV_fchown (__NR_SYSV + 152) +#define __NR_SYSV_fchmod (__NR_SYSV + 153) +#define __NR_SYSV_wait3 (__NR_SYSV + 154) +#define __NR_SYSV_socketpair (__NR_SYSV + 155) +#define __NR_SYSV_sysinfo (__NR_SYSV + 156) +#define __NR_SYSV_nuname (__NR_SYSV + 157) +#define __NR_SYSV_xstat (__NR_SYSV + 158) +#define __NR_SYSV_lxstat (__NR_SYSV + 159) +#define __NR_SYSV_fxstat (__NR_SYSV + 160) +#define __NR_SYSV_xmknod (__NR_SYSV + 161) +#define __NR_SYSV_ksigaction (__NR_SYSV + 162) +#define __NR_SYSV_sigpending (__NR_SYSV + 163) +#define __NR_SYSV_sigprocmask (__NR_SYSV + 164) +#define __NR_SYSV_sigsuspend (__NR_SYSV + 165) +#define __NR_SYSV_sigpoll (__NR_SYSV + 166) +#define __NR_SYSV_swapctl (__NR_SYSV + 167) +#define __NR_SYSV_getcontext (__NR_SYSV + 168) +#define __NR_SYSV_setcontext (__NR_SYSV + 169) +#define __NR_SYSV_waitsys (__NR_SYSV + 170) +#define __NR_SYSV_sigstack (__NR_SYSV + 171) +#define __NR_SYSV_sigaltstack (__NR_SYSV + 172) +#define __NR_SYSV_sigsendset (__NR_SYSV + 173) +#define __NR_SYSV_statvfs (__NR_SYSV + 174) +#define __NR_SYSV_fstatvfs (__NR_SYSV + 175) +#define __NR_SYSV_getpmsg (__NR_SYSV + 176) +#define __NR_SYSV_putpmsg (__NR_SYSV + 177) +#define __NR_SYSV_lchown (__NR_SYSV + 178) +#define __NR_SYSV_priocntl (__NR_SYSV + 179) +#define __NR_SYSV_ksigqueue (__NR_SYSV + 180) +#define __NR_SYSV_readv (__NR_SYSV + 181) +#define __NR_SYSV_writev (__NR_SYSV + 182) +#define __NR_SYSV_truncate64 (__NR_SYSV + 183) +#define __NR_SYSV_ftruncate64 (__NR_SYSV + 184) +#define __NR_SYSV_mmap64 (__NR_SYSV + 185) +#define __NR_SYSV_dmi (__NR_SYSV + 186) +#define __NR_SYSV_pread (__NR_SYSV + 187) +#define __NR_SYSV_pwrite (__NR_SYSV + 188) + +/* + * BSD 4.3 syscalls are in the range from 2000 to 2999 + */ +#define __NR_BSD43 2000 +#define __NR_BSD43_syscall (__NR_BSD43 + 0) +#define __NR_BSD43_exit (__NR_BSD43 + 1) +#define __NR_BSD43_fork (__NR_BSD43 + 2) +#define __NR_BSD43_read (__NR_BSD43 + 3) +#define __NR_BSD43_write (__NR_BSD43 + 4) +#define __NR_BSD43_open (__NR_BSD43 + 5) +#define __NR_BSD43_close (__NR_BSD43 + 6) +#define __NR_BSD43_wait (__NR_BSD43 + 7) +#define __NR_BSD43_creat (__NR_BSD43 + 8) +#define __NR_BSD43_link (__NR_BSD43 + 9) +#define __NR_BSD43_unlink (__NR_BSD43 + 10) +#define __NR_BSD43_exec (__NR_BSD43 + 11) +#define __NR_BSD43_chdir (__NR_BSD43 + 12) +#define __NR_BSD43_time (__NR_BSD43 + 13) +#define __NR_BSD43_mknod (__NR_BSD43 + 14) +#define __NR_BSD43_chmod (__NR_BSD43 + 15) +#define __NR_BSD43_chown (__NR_BSD43 + 16) +#define __NR_BSD43_sbreak (__NR_BSD43 + 17) +#define __NR_BSD43_oldstat (__NR_BSD43 + 18) +#define __NR_BSD43_lseek (__NR_BSD43 + 19) +#define __NR_BSD43_getpid (__NR_BSD43 + 20) +#define __NR_BSD43_oldmount (__NR_BSD43 + 21) +#define __NR_BSD43_umount (__NR_BSD43 + 22) +#define __NR_BSD43_setuid (__NR_BSD43 + 23) +#define __NR_BSD43_getuid (__NR_BSD43 + 24) +#define __NR_BSD43_stime (__NR_BSD43 + 25) +#define __NR_BSD43_ptrace (__NR_BSD43 + 26) +#define __NR_BSD43_alarm (__NR_BSD43 + 27) +#define __NR_BSD43_oldfstat (__NR_BSD43 + 28) +#define __NR_BSD43_pause (__NR_BSD43 + 29) +#define __NR_BSD43_utime (__NR_BSD43 + 30) +#define __NR_BSD43_stty (__NR_BSD43 + 31) +#define __NR_BSD43_gtty (__NR_BSD43 + 32) +#define __NR_BSD43_access (__NR_BSD43 + 33) +#define __NR_BSD43_nice (__NR_BSD43 + 34) +#define __NR_BSD43_ftime (__NR_BSD43 + 35) +#define __NR_BSD43_sync (__NR_BSD43 + 36) +#define __NR_BSD43_kill (__NR_BSD43 + 37) +#define __NR_BSD43_stat (__NR_BSD43 + 38) +#define __NR_BSD43_oldsetpgrp (__NR_BSD43 + 39) +#define __NR_BSD43_lstat (__NR_BSD43 + 40) +#define __NR_BSD43_dup (__NR_BSD43 + 41) +#define __NR_BSD43_pipe (__NR_BSD43 + 42) +#define __NR_BSD43_times (__NR_BSD43 + 43) +#define __NR_BSD43_profil (__NR_BSD43 + 44) +#define __NR_BSD43_msgsys (__NR_BSD43 + 45) +#define __NR_BSD43_setgid (__NR_BSD43 + 46) +#define __NR_BSD43_getgid (__NR_BSD43 + 47) +#define __NR_BSD43_ssig (__NR_BSD43 + 48) +#define __NR_BSD43_reserved1 (__NR_BSD43 + 49) +#define __NR_BSD43_reserved2 (__NR_BSD43 + 50) +#define __NR_BSD43_sysacct (__NR_BSD43 + 51) +#define __NR_BSD43_phys (__NR_BSD43 + 52) +#define __NR_BSD43_lock (__NR_BSD43 + 53) +#define __NR_BSD43_ioctl (__NR_BSD43 + 54) +#define __NR_BSD43_reboot (__NR_BSD43 + 55) +#define __NR_BSD43_mpxchan (__NR_BSD43 + 56) +#define __NR_BSD43_symlink (__NR_BSD43 + 57) +#define __NR_BSD43_readlink (__NR_BSD43 + 58) +#define __NR_BSD43_execve (__NR_BSD43 + 59) +#define __NR_BSD43_umask (__NR_BSD43 + 60) +#define __NR_BSD43_chroot (__NR_BSD43 + 61) +#define __NR_BSD43_fstat (__NR_BSD43 + 62) +#define __NR_BSD43_reserved3 (__NR_BSD43 + 63) +#define __NR_BSD43_getpagesize (__NR_BSD43 + 64) +#define __NR_BSD43_mremap (__NR_BSD43 + 65) +#define __NR_BSD43_vfork (__NR_BSD43 + 66) +#define __NR_BSD43_vread (__NR_BSD43 + 67) +#define __NR_BSD43_vwrite (__NR_BSD43 + 68) +#define __NR_BSD43_sbrk (__NR_BSD43 + 69) +#define __NR_BSD43_sstk (__NR_BSD43 + 70) +#define __NR_BSD43_mmap (__NR_BSD43 + 71) +#define __NR_BSD43_vadvise (__NR_BSD43 + 72) +#define __NR_BSD43_munmap (__NR_BSD43 + 73) +#define __NR_BSD43_mprotect (__NR_BSD43 + 74) +#define __NR_BSD43_madvise (__NR_BSD43 + 75) +#define __NR_BSD43_vhangup (__NR_BSD43 + 76) +#define __NR_BSD43_vlimit (__NR_BSD43 + 77) +#define __NR_BSD43_mincore (__NR_BSD43 + 78) +#define __NR_BSD43_getgroups (__NR_BSD43 + 79) +#define __NR_BSD43_setgroups (__NR_BSD43 + 80) +#define __NR_BSD43_getpgrp (__NR_BSD43 + 81) +#define __NR_BSD43_setpgrp (__NR_BSD43 + 82) +#define __NR_BSD43_setitimer (__NR_BSD43 + 83) +#define __NR_BSD43_wait3 (__NR_BSD43 + 84) +#define __NR_BSD43_swapon (__NR_BSD43 + 85) +#define __NR_BSD43_getitimer (__NR_BSD43 + 86) +#define __NR_BSD43_gethostname (__NR_BSD43 + 87) +#define __NR_BSD43_sethostname (__NR_BSD43 + 88) +#define __NR_BSD43_getdtablesize (__NR_BSD43 + 89) +#define __NR_BSD43_dup2 (__NR_BSD43 + 90) +#define __NR_BSD43_getdopt (__NR_BSD43 + 91) +#define __NR_BSD43_fcntl (__NR_BSD43 + 92) +#define __NR_BSD43_select (__NR_BSD43 + 93) +#define __NR_BSD43_setdopt (__NR_BSD43 + 94) +#define __NR_BSD43_fsync (__NR_BSD43 + 95) +#define __NR_BSD43_setpriority (__NR_BSD43 + 96) +#define __NR_BSD43_socket (__NR_BSD43 + 97) +#define __NR_BSD43_connect (__NR_BSD43 + 98) +#define __NR_BSD43_oldaccept (__NR_BSD43 + 99) +#define __NR_BSD43_getpriority (__NR_BSD43 + 100) +#define __NR_BSD43_send (__NR_BSD43 + 101) +#define __NR_BSD43_recv (__NR_BSD43 + 102) +#define __NR_BSD43_sigreturn (__NR_BSD43 + 103) +#define __NR_BSD43_bind (__NR_BSD43 + 104) +#define __NR_BSD43_setsockopt (__NR_BSD43 + 105) +#define __NR_BSD43_listen (__NR_BSD43 + 106) +#define __NR_BSD43_vtimes (__NR_BSD43 + 107) +#define __NR_BSD43_sigvec (__NR_BSD43 + 108) +#define __NR_BSD43_sigblock (__NR_BSD43 + 109) +#define __NR_BSD43_sigsetmask (__NR_BSD43 + 110) +#define __NR_BSD43_sigpause (__NR_BSD43 + 111) +#define __NR_BSD43_sigstack (__NR_BSD43 + 112) +#define __NR_BSD43_oldrecvmsg (__NR_BSD43 + 113) +#define __NR_BSD43_oldsendmsg (__NR_BSD43 + 114) +#define __NR_BSD43_vtrace (__NR_BSD43 + 115) +#define __NR_BSD43_gettimeofday (__NR_BSD43 + 116) +#define __NR_BSD43_getrusage (__NR_BSD43 + 117) +#define __NR_BSD43_getsockopt (__NR_BSD43 + 118) +#define __NR_BSD43_reserved4 (__NR_BSD43 + 119) +#define __NR_BSD43_readv (__NR_BSD43 + 120) +#define __NR_BSD43_writev (__NR_BSD43 + 121) +#define __NR_BSD43_settimeofday (__NR_BSD43 + 122) +#define __NR_BSD43_fchown (__NR_BSD43 + 123) +#define __NR_BSD43_fchmod (__NR_BSD43 + 124) +#define __NR_BSD43_oldrecvfrom (__NR_BSD43 + 125) +#define __NR_BSD43_setreuid (__NR_BSD43 + 126) +#define __NR_BSD43_setregid (__NR_BSD43 + 127) +#define __NR_BSD43_rename (__NR_BSD43 + 128) +#define __NR_BSD43_truncate (__NR_BSD43 + 129) +#define __NR_BSD43_ftruncate (__NR_BSD43 + 130) +#define __NR_BSD43_flock (__NR_BSD43 + 131) +#define __NR_BSD43_semsys (__NR_BSD43 + 132) +#define __NR_BSD43_sendto (__NR_BSD43 + 133) +#define __NR_BSD43_shutdown (__NR_BSD43 + 134) +#define __NR_BSD43_socketpair (__NR_BSD43 + 135) +#define __NR_BSD43_mkdir (__NR_BSD43 + 136) +#define __NR_BSD43_rmdir (__NR_BSD43 + 137) +#define __NR_BSD43_utimes (__NR_BSD43 + 138) +#define __NR_BSD43_sigcleanup (__NR_BSD43 + 139) +#define __NR_BSD43_adjtime (__NR_BSD43 + 140) +#define __NR_BSD43_oldgetpeername (__NR_BSD43 + 141) +#define __NR_BSD43_gethostid (__NR_BSD43 + 142) +#define __NR_BSD43_sethostid (__NR_BSD43 + 143) +#define __NR_BSD43_getrlimit (__NR_BSD43 + 144) +#define __NR_BSD43_setrlimit (__NR_BSD43 + 145) +#define __NR_BSD43_killpg (__NR_BSD43 + 146) +#define __NR_BSD43_shmsys (__NR_BSD43 + 147) +#define __NR_BSD43_quota (__NR_BSD43 + 148) +#define __NR_BSD43_qquota (__NR_BSD43 + 149) +#define __NR_BSD43_oldgetsockname (__NR_BSD43 + 150) +#define __NR_BSD43_sysmips (__NR_BSD43 + 151) +#define __NR_BSD43_cacheflush (__NR_BSD43 + 152) +#define __NR_BSD43_cachectl (__NR_BSD43 + 153) +#define __NR_BSD43_debug (__NR_BSD43 + 154) +#define __NR_BSD43_reserved5 (__NR_BSD43 + 155) +#define __NR_BSD43_reserved6 (__NR_BSD43 + 156) +#define __NR_BSD43_nfs_mount (__NR_BSD43 + 157) +#define __NR_BSD43_nfs_svc (__NR_BSD43 + 158) +#define __NR_BSD43_getdirentries (__NR_BSD43 + 159) +#define __NR_BSD43_statfs (__NR_BSD43 + 160) +#define __NR_BSD43_fstatfs (__NR_BSD43 + 161) +#define __NR_BSD43_unmount (__NR_BSD43 + 162) +#define __NR_BSD43_async_daemon (__NR_BSD43 + 163) +#define __NR_BSD43_nfs_getfh (__NR_BSD43 + 164) +#define __NR_BSD43_getdomainname (__NR_BSD43 + 165) +#define __NR_BSD43_setdomainname (__NR_BSD43 + 166) +#define __NR_BSD43_pcfs_mount (__NR_BSD43 + 167) +#define __NR_BSD43_quotactl (__NR_BSD43 + 168) +#define __NR_BSD43_oldexportfs (__NR_BSD43 + 169) +#define __NR_BSD43_smount (__NR_BSD43 + 170) +#define __NR_BSD43_mipshwconf (__NR_BSD43 + 171) +#define __NR_BSD43_exportfs (__NR_BSD43 + 172) +#define __NR_BSD43_nfsfh_open (__NR_BSD43 + 173) +#define __NR_BSD43_libattach (__NR_BSD43 + 174) +#define __NR_BSD43_libdetach (__NR_BSD43 + 175) +#define __NR_BSD43_accept (__NR_BSD43 + 176) +#define __NR_BSD43_reserved7 (__NR_BSD43 + 177) +#define __NR_BSD43_reserved8 (__NR_BSD43 + 178) +#define __NR_BSD43_recvmsg (__NR_BSD43 + 179) +#define __NR_BSD43_recvfrom (__NR_BSD43 + 180) +#define __NR_BSD43_sendmsg (__NR_BSD43 + 181) +#define __NR_BSD43_getpeername (__NR_BSD43 + 182) +#define __NR_BSD43_getsockname (__NR_BSD43 + 183) +#define __NR_BSD43_aread (__NR_BSD43 + 184) +#define __NR_BSD43_awrite (__NR_BSD43 + 185) +#define __NR_BSD43_listio (__NR_BSD43 + 186) +#define __NR_BSD43_acancel (__NR_BSD43 + 187) +#define __NR_BSD43_astatus (__NR_BSD43 + 188) +#define __NR_BSD43_await (__NR_BSD43 + 189) +#define __NR_BSD43_areadv (__NR_BSD43 + 190) +#define __NR_BSD43_awritev (__NR_BSD43 + 191) + +/* + * POSIX syscalls are in the range from 3000 to 3999 + */ +#define __NR_POSIX 3000 +#define __NR_POSIX_syscall (__NR_POSIX + 0) +#define __NR_POSIX_exit (__NR_POSIX + 1) +#define __NR_POSIX_fork (__NR_POSIX + 2) +#define __NR_POSIX_read (__NR_POSIX + 3) +#define __NR_POSIX_write (__NR_POSIX + 4) +#define __NR_POSIX_open (__NR_POSIX + 5) +#define __NR_POSIX_close (__NR_POSIX + 6) +#define __NR_POSIX_wait (__NR_POSIX + 7) +#define __NR_POSIX_creat (__NR_POSIX + 8) +#define __NR_POSIX_link (__NR_POSIX + 9) +#define __NR_POSIX_unlink (__NR_POSIX + 10) +#define __NR_POSIX_exec (__NR_POSIX + 11) +#define __NR_POSIX_chdir (__NR_POSIX + 12) +#define __NR_POSIX_gtime (__NR_POSIX + 13) +#define __NR_POSIX_mknod (__NR_POSIX + 14) +#define __NR_POSIX_chmod (__NR_POSIX + 15) +#define __NR_POSIX_chown (__NR_POSIX + 16) +#define __NR_POSIX_sbreak (__NR_POSIX + 17) +#define __NR_POSIX_stat (__NR_POSIX + 18) +#define __NR_POSIX_lseek (__NR_POSIX + 19) +#define __NR_POSIX_getpid (__NR_POSIX + 20) +#define __NR_POSIX_mount (__NR_POSIX + 21) +#define __NR_POSIX_umount (__NR_POSIX + 22) +#define __NR_POSIX_setuid (__NR_POSIX + 23) +#define __NR_POSIX_getuid (__NR_POSIX + 24) +#define __NR_POSIX_stime (__NR_POSIX + 25) +#define __NR_POSIX_ptrace (__NR_POSIX + 26) +#define __NR_POSIX_alarm (__NR_POSIX + 27) +#define __NR_POSIX_fstat (__NR_POSIX + 28) +#define __NR_POSIX_pause (__NR_POSIX + 29) +#define __NR_POSIX_utime (__NR_POSIX + 30) +#define __NR_POSIX_stty (__NR_POSIX + 31) +#define __NR_POSIX_gtty (__NR_POSIX + 32) +#define __NR_POSIX_access (__NR_POSIX + 33) +#define __NR_POSIX_nice (__NR_POSIX + 34) +#define __NR_POSIX_statfs (__NR_POSIX + 35) +#define __NR_POSIX_sync (__NR_POSIX + 36) +#define __NR_POSIX_kill (__NR_POSIX + 37) +#define __NR_POSIX_fstatfs (__NR_POSIX + 38) +#define __NR_POSIX_getpgrp (__NR_POSIX + 39) +#define __NR_POSIX_syssgi (__NR_POSIX + 40) +#define __NR_POSIX_dup (__NR_POSIX + 41) +#define __NR_POSIX_pipe (__NR_POSIX + 42) +#define __NR_POSIX_times (__NR_POSIX + 43) +#define __NR_POSIX_profil (__NR_POSIX + 44) +#define __NR_POSIX_lock (__NR_POSIX + 45) +#define __NR_POSIX_setgid (__NR_POSIX + 46) +#define __NR_POSIX_getgid (__NR_POSIX + 47) +#define __NR_POSIX_sig (__NR_POSIX + 48) +#define __NR_POSIX_msgsys (__NR_POSIX + 49) +#define __NR_POSIX_sysmips (__NR_POSIX + 50) +#define __NR_POSIX_sysacct (__NR_POSIX + 51) +#define __NR_POSIX_shmsys (__NR_POSIX + 52) +#define __NR_POSIX_semsys (__NR_POSIX + 53) +#define __NR_POSIX_ioctl (__NR_POSIX + 54) +#define __NR_POSIX_uadmin (__NR_POSIX + 55) +#define __NR_POSIX_exch (__NR_POSIX + 56) +#define __NR_POSIX_utssys (__NR_POSIX + 57) +#define __NR_POSIX_USG_reserved1 (__NR_POSIX + 58) +#define __NR_POSIX_exece (__NR_POSIX + 59) +#define __NR_POSIX_umask (__NR_POSIX + 60) +#define __NR_POSIX_chroot (__NR_POSIX + 61) +#define __NR_POSIX_fcntl (__NR_POSIX + 62) +#define __NR_POSIX_ulimit (__NR_POSIX + 63) +#define __NR_POSIX_SAFARI4_reserved1 (__NR_POSIX + 64) +#define __NR_POSIX_SAFARI4_reserved2 (__NR_POSIX + 65) +#define __NR_POSIX_SAFARI4_reserved3 (__NR_POSIX + 66) +#define __NR_POSIX_SAFARI4_reserved4 (__NR_POSIX + 67) +#define __NR_POSIX_SAFARI4_reserved5 (__NR_POSIX + 68) +#define __NR_POSIX_SAFARI4_reserved6 (__NR_POSIX + 69) +#define __NR_POSIX_advfs (__NR_POSIX + 70) +#define __NR_POSIX_unadvfs (__NR_POSIX + 71) +#define __NR_POSIX_rmount (__NR_POSIX + 72) +#define __NR_POSIX_rumount (__NR_POSIX + 73) +#define __NR_POSIX_rfstart (__NR_POSIX + 74) +#define __NR_POSIX_reserved1 (__NR_POSIX + 75) +#define __NR_POSIX_rdebug (__NR_POSIX + 76) +#define __NR_POSIX_rfstop (__NR_POSIX + 77) +#define __NR_POSIX_rfsys (__NR_POSIX + 78) +#define __NR_POSIX_rmdir (__NR_POSIX + 79) +#define __NR_POSIX_mkdir (__NR_POSIX + 80) +#define __NR_POSIX_getdents (__NR_POSIX + 81) +#define __NR_POSIX_sginap (__NR_POSIX + 82) +#define __NR_POSIX_sgikopt (__NR_POSIX + 83) +#define __NR_POSIX_sysfs (__NR_POSIX + 84) +#define __NR_POSIX_getmsg (__NR_POSIX + 85) +#define __NR_POSIX_putmsg (__NR_POSIX + 86) +#define __NR_POSIX_poll (__NR_POSIX + 87) +#define __NR_POSIX_sigreturn (__NR_POSIX + 88) +#define __NR_POSIX_accept (__NR_POSIX + 89) +#define __NR_POSIX_bind (__NR_POSIX + 90) +#define __NR_POSIX_connect (__NR_POSIX + 91) +#define __NR_POSIX_gethostid (__NR_POSIX + 92) +#define __NR_POSIX_getpeername (__NR_POSIX + 93) +#define __NR_POSIX_getsockname (__NR_POSIX + 94) +#define __NR_POSIX_getsockopt (__NR_POSIX + 95) +#define __NR_POSIX_listen (__NR_POSIX + 96) +#define __NR_POSIX_recv (__NR_POSIX + 97) +#define __NR_POSIX_recvfrom (__NR_POSIX + 98) +#define __NR_POSIX_recvmsg (__NR_POSIX + 99) +#define __NR_POSIX_select (__NR_POSIX + 100) +#define __NR_POSIX_send (__NR_POSIX + 101) +#define __NR_POSIX_sendmsg (__NR_POSIX + 102) +#define __NR_POSIX_sendto (__NR_POSIX + 103) +#define __NR_POSIX_sethostid (__NR_POSIX + 104) +#define __NR_POSIX_setsockopt (__NR_POSIX + 105) +#define __NR_POSIX_shutdown (__NR_POSIX + 106) +#define __NR_POSIX_socket (__NR_POSIX + 107) +#define __NR_POSIX_gethostname (__NR_POSIX + 108) +#define __NR_POSIX_sethostname (__NR_POSIX + 109) +#define __NR_POSIX_getdomainname (__NR_POSIX + 110) +#define __NR_POSIX_setdomainname (__NR_POSIX + 111) +#define __NR_POSIX_truncate (__NR_POSIX + 112) +#define __NR_POSIX_ftruncate (__NR_POSIX + 113) +#define __NR_POSIX_rename (__NR_POSIX + 114) +#define __NR_POSIX_symlink (__NR_POSIX + 115) +#define __NR_POSIX_readlink (__NR_POSIX + 116) +#define __NR_POSIX_lstat (__NR_POSIX + 117) +#define __NR_POSIX_nfs_mount (__NR_POSIX + 118) +#define __NR_POSIX_nfs_svc (__NR_POSIX + 119) +#define __NR_POSIX_nfs_getfh (__NR_POSIX + 120) +#define __NR_POSIX_async_daemon (__NR_POSIX + 121) +#define __NR_POSIX_exportfs (__NR_POSIX + 122) +#define __NR_POSIX_SGI_setregid (__NR_POSIX + 123) +#define __NR_POSIX_SGI_setreuid (__NR_POSIX + 124) +#define __NR_POSIX_getitimer (__NR_POSIX + 125) +#define __NR_POSIX_setitimer (__NR_POSIX + 126) +#define __NR_POSIX_adjtime (__NR_POSIX + 127) +#define __NR_POSIX_SGI_bsdgettime (__NR_POSIX + 128) +#define __NR_POSIX_SGI_sproc (__NR_POSIX + 129) +#define __NR_POSIX_SGI_prctl (__NR_POSIX + 130) +#define __NR_POSIX_SGI_blkproc (__NR_POSIX + 131) +#define __NR_POSIX_SGI_reserved1 (__NR_POSIX + 132) +#define __NR_POSIX_SGI_sgigsc (__NR_POSIX + 133) +#define __NR_POSIX_SGI_mmap (__NR_POSIX + 134) +#define __NR_POSIX_SGI_munmap (__NR_POSIX + 135) +#define __NR_POSIX_SGI_mprotect (__NR_POSIX + 136) +#define __NR_POSIX_SGI_msync (__NR_POSIX + 137) +#define __NR_POSIX_SGI_madvise (__NR_POSIX + 138) +#define __NR_POSIX_SGI_mpin (__NR_POSIX + 139) +#define __NR_POSIX_SGI_getpagesize (__NR_POSIX + 140) +#define __NR_POSIX_SGI_libattach (__NR_POSIX + 141) +#define __NR_POSIX_SGI_libdetach (__NR_POSIX + 142) +#define __NR_POSIX_SGI_getpgrp (__NR_POSIX + 143) +#define __NR_POSIX_SGI_setpgrp (__NR_POSIX + 144) +#define __NR_POSIX_SGI_reserved2 (__NR_POSIX + 145) +#define __NR_POSIX_SGI_reserved3 (__NR_POSIX + 146) +#define __NR_POSIX_SGI_reserved4 (__NR_POSIX + 147) +#define __NR_POSIX_SGI_reserved5 (__NR_POSIX + 148) +#define __NR_POSIX_SGI_reserved6 (__NR_POSIX + 149) +#define __NR_POSIX_cacheflush (__NR_POSIX + 150) +#define __NR_POSIX_cachectl (__NR_POSIX + 151) +#define __NR_POSIX_fchown (__NR_POSIX + 152) +#define __NR_POSIX_fchmod (__NR_POSIX + 153) +#define __NR_POSIX_wait3 (__NR_POSIX + 154) +#define __NR_POSIX_mmap (__NR_POSIX + 155) +#define __NR_POSIX_munmap (__NR_POSIX + 156) +#define __NR_POSIX_madvise (__NR_POSIX + 157) +#define __NR_POSIX_BSD_getpagesize (__NR_POSIX + 158) +#define __NR_POSIX_setreuid (__NR_POSIX + 159) +#define __NR_POSIX_setregid (__NR_POSIX + 160) +#define __NR_POSIX_setpgid (__NR_POSIX + 161) +#define __NR_POSIX_getgroups (__NR_POSIX + 162) +#define __NR_POSIX_setgroups (__NR_POSIX + 163) +#define __NR_POSIX_gettimeofday (__NR_POSIX + 164) +#define __NR_POSIX_getrusage (__NR_POSIX + 165) +#define __NR_POSIX_getrlimit (__NR_POSIX + 166) +#define __NR_POSIX_setrlimit (__NR_POSIX + 167) +#define __NR_POSIX_waitpid (__NR_POSIX + 168) +#define __NR_POSIX_dup2 (__NR_POSIX + 169) +#define __NR_POSIX_reserved2 (__NR_POSIX + 170) +#define __NR_POSIX_reserved3 (__NR_POSIX + 171) +#define __NR_POSIX_reserved4 (__NR_POSIX + 172) +#define __NR_POSIX_reserved5 (__NR_POSIX + 173) +#define __NR_POSIX_reserved6 (__NR_POSIX + 174) +#define __NR_POSIX_reserved7 (__NR_POSIX + 175) +#define __NR_POSIX_reserved8 (__NR_POSIX + 176) +#define __NR_POSIX_reserved9 (__NR_POSIX + 177) +#define __NR_POSIX_reserved10 (__NR_POSIX + 178) +#define __NR_POSIX_reserved11 (__NR_POSIX + 179) +#define __NR_POSIX_reserved12 (__NR_POSIX + 180) +#define __NR_POSIX_reserved13 (__NR_POSIX + 181) +#define __NR_POSIX_reserved14 (__NR_POSIX + 182) +#define __NR_POSIX_reserved15 (__NR_POSIX + 183) +#define __NR_POSIX_reserved16 (__NR_POSIX + 184) +#define __NR_POSIX_reserved17 (__NR_POSIX + 185) +#define __NR_POSIX_reserved18 (__NR_POSIX + 186) +#define __NR_POSIX_reserved19 (__NR_POSIX + 187) +#define __NR_POSIX_reserved20 (__NR_POSIX + 188) +#define __NR_POSIX_reserved21 (__NR_POSIX + 189) +#define __NR_POSIX_reserved22 (__NR_POSIX + 190) +#define __NR_POSIX_reserved23 (__NR_POSIX + 191) +#define __NR_POSIX_reserved24 (__NR_POSIX + 192) +#define __NR_POSIX_reserved25 (__NR_POSIX + 193) +#define __NR_POSIX_reserved26 (__NR_POSIX + 194) +#define __NR_POSIX_reserved27 (__NR_POSIX + 195) +#define __NR_POSIX_reserved28 (__NR_POSIX + 196) +#define __NR_POSIX_reserved29 (__NR_POSIX + 197) +#define __NR_POSIX_reserved30 (__NR_POSIX + 198) +#define __NR_POSIX_reserved31 (__NR_POSIX + 199) +#define __NR_POSIX_reserved32 (__NR_POSIX + 200) +#define __NR_POSIX_reserved33 (__NR_POSIX + 201) +#define __NR_POSIX_reserved34 (__NR_POSIX + 202) +#define __NR_POSIX_reserved35 (__NR_POSIX + 203) +#define __NR_POSIX_reserved36 (__NR_POSIX + 204) +#define __NR_POSIX_reserved37 (__NR_POSIX + 205) +#define __NR_POSIX_reserved38 (__NR_POSIX + 206) +#define __NR_POSIX_reserved39 (__NR_POSIX + 207) +#define __NR_POSIX_reserved40 (__NR_POSIX + 208) +#define __NR_POSIX_reserved41 (__NR_POSIX + 209) +#define __NR_POSIX_reserved42 (__NR_POSIX + 210) +#define __NR_POSIX_reserved43 (__NR_POSIX + 211) +#define __NR_POSIX_reserved44 (__NR_POSIX + 212) +#define __NR_POSIX_reserved45 (__NR_POSIX + 213) +#define __NR_POSIX_reserved46 (__NR_POSIX + 214) +#define __NR_POSIX_reserved47 (__NR_POSIX + 215) +#define __NR_POSIX_reserved48 (__NR_POSIX + 216) +#define __NR_POSIX_reserved49 (__NR_POSIX + 217) +#define __NR_POSIX_reserved50 (__NR_POSIX + 218) +#define __NR_POSIX_reserved51 (__NR_POSIX + 219) +#define __NR_POSIX_reserved52 (__NR_POSIX + 220) +#define __NR_POSIX_reserved53 (__NR_POSIX + 221) +#define __NR_POSIX_reserved54 (__NR_POSIX + 222) +#define __NR_POSIX_reserved55 (__NR_POSIX + 223) +#define __NR_POSIX_reserved56 (__NR_POSIX + 224) +#define __NR_POSIX_reserved57 (__NR_POSIX + 225) +#define __NR_POSIX_reserved58 (__NR_POSIX + 226) +#define __NR_POSIX_reserved59 (__NR_POSIX + 227) +#define __NR_POSIX_reserved60 (__NR_POSIX + 228) +#define __NR_POSIX_reserved61 (__NR_POSIX + 229) +#define __NR_POSIX_reserved62 (__NR_POSIX + 230) +#define __NR_POSIX_reserved63 (__NR_POSIX + 231) +#define __NR_POSIX_reserved64 (__NR_POSIX + 232) +#define __NR_POSIX_reserved65 (__NR_POSIX + 233) +#define __NR_POSIX_reserved66 (__NR_POSIX + 234) +#define __NR_POSIX_reserved67 (__NR_POSIX + 235) +#define __NR_POSIX_reserved68 (__NR_POSIX + 236) +#define __NR_POSIX_reserved69 (__NR_POSIX + 237) +#define __NR_POSIX_reserved70 (__NR_POSIX + 238) +#define __NR_POSIX_reserved71 (__NR_POSIX + 239) +#define __NR_POSIX_reserved72 (__NR_POSIX + 240) +#define __NR_POSIX_reserved73 (__NR_POSIX + 241) +#define __NR_POSIX_reserved74 (__NR_POSIX + 242) +#define __NR_POSIX_reserved75 (__NR_POSIX + 243) +#define __NR_POSIX_reserved76 (__NR_POSIX + 244) +#define __NR_POSIX_reserved77 (__NR_POSIX + 245) +#define __NR_POSIX_reserved78 (__NR_POSIX + 246) +#define __NR_POSIX_reserved79 (__NR_POSIX + 247) +#define __NR_POSIX_reserved80 (__NR_POSIX + 248) +#define __NR_POSIX_reserved81 (__NR_POSIX + 249) +#define __NR_POSIX_reserved82 (__NR_POSIX + 250) +#define __NR_POSIX_reserved83 (__NR_POSIX + 251) +#define __NR_POSIX_reserved84 (__NR_POSIX + 252) +#define __NR_POSIX_reserved85 (__NR_POSIX + 253) +#define __NR_POSIX_reserved86 (__NR_POSIX + 254) +#define __NR_POSIX_reserved87 (__NR_POSIX + 255) +#define __NR_POSIX_reserved88 (__NR_POSIX + 256) +#define __NR_POSIX_reserved89 (__NR_POSIX + 257) +#define __NR_POSIX_reserved90 (__NR_POSIX + 258) +#define __NR_POSIX_reserved91 (__NR_POSIX + 259) +#define __NR_POSIX_netboot (__NR_POSIX + 260) +#define __NR_POSIX_netunboot (__NR_POSIX + 261) +#define __NR_POSIX_rdump (__NR_POSIX + 262) +#define __NR_POSIX_setsid (__NR_POSIX + 263) +#define __NR_POSIX_getmaxsig (__NR_POSIX + 264) +#define __NR_POSIX_sigpending (__NR_POSIX + 265) +#define __NR_POSIX_sigprocmask (__NR_POSIX + 266) +#define __NR_POSIX_sigsuspend (__NR_POSIX + 267) +#define __NR_POSIX_sigaction (__NR_POSIX + 268) +#define __NR_POSIX_MIPS_reserved1 (__NR_POSIX + 269) +#define __NR_POSIX_MIPS_reserved2 (__NR_POSIX + 270) +#define __NR_POSIX_MIPS_reserved3 (__NR_POSIX + 271) +#define __NR_POSIX_MIPS_reserved4 (__NR_POSIX + 272) +#define __NR_POSIX_MIPS_reserved5 (__NR_POSIX + 273) +#define __NR_POSIX_MIPS_reserved6 (__NR_POSIX + 274) +#define __NR_POSIX_MIPS_reserved7 (__NR_POSIX + 275) +#define __NR_POSIX_MIPS_reserved8 (__NR_POSIX + 276) +#define __NR_POSIX_MIPS_reserved9 (__NR_POSIX + 277) +#define __NR_POSIX_MIPS_reserved10 (__NR_POSIX + 278) +#define __NR_POSIX_MIPS_reserved11 (__NR_POSIX + 279) +#define __NR_POSIX_TANDEM_reserved1 (__NR_POSIX + 280) +#define __NR_POSIX_TANDEM_reserved2 (__NR_POSIX + 281) +#define __NR_POSIX_TANDEM_reserved3 (__NR_POSIX + 282) +#define __NR_POSIX_TANDEM_reserved4 (__NR_POSIX + 283) +#define __NR_POSIX_TANDEM_reserved5 (__NR_POSIX + 284) +#define __NR_POSIX_TANDEM_reserved6 (__NR_POSIX + 285) +#define __NR_POSIX_TANDEM_reserved7 (__NR_POSIX + 286) +#define __NR_POSIX_TANDEM_reserved8 (__NR_POSIX + 287) +#define __NR_POSIX_TANDEM_reserved9 (__NR_POSIX + 288) +#define __NR_POSIX_TANDEM_reserved10 (__NR_POSIX + 289) +#define __NR_POSIX_TANDEM_reserved11 (__NR_POSIX + 290) +#define __NR_POSIX_TANDEM_reserved12 (__NR_POSIX + 291) +#define __NR_POSIX_TANDEM_reserved13 (__NR_POSIX + 292) +#define __NR_POSIX_TANDEM_reserved14 (__NR_POSIX + 293) +#define __NR_POSIX_TANDEM_reserved15 (__NR_POSIX + 294) +#define __NR_POSIX_TANDEM_reserved16 (__NR_POSIX + 295) +#define __NR_POSIX_TANDEM_reserved17 (__NR_POSIX + 296) +#define __NR_POSIX_TANDEM_reserved18 (__NR_POSIX + 297) +#define __NR_POSIX_TANDEM_reserved19 (__NR_POSIX + 298) +#define __NR_POSIX_TANDEM_reserved20 (__NR_POSIX + 299) +#define __NR_POSIX_SGI_reserved7 (__NR_POSIX + 300) +#define __NR_POSIX_SGI_reserved8 (__NR_POSIX + 301) +#define __NR_POSIX_SGI_reserved9 (__NR_POSIX + 302) +#define __NR_POSIX_SGI_reserved10 (__NR_POSIX + 303) +#define __NR_POSIX_SGI_reserved11 (__NR_POSIX + 304) +#define __NR_POSIX_SGI_reserved12 (__NR_POSIX + 305) +#define __NR_POSIX_SGI_reserved13 (__NR_POSIX + 306) +#define __NR_POSIX_SGI_reserved14 (__NR_POSIX + 307) +#define __NR_POSIX_SGI_reserved15 (__NR_POSIX + 308) +#define __NR_POSIX_SGI_reserved16 (__NR_POSIX + 309) +#define __NR_POSIX_SGI_reserved17 (__NR_POSIX + 310) +#define __NR_POSIX_SGI_reserved18 (__NR_POSIX + 311) +#define __NR_POSIX_SGI_reserved19 (__NR_POSIX + 312) +#define __NR_POSIX_SGI_reserved20 (__NR_POSIX + 313) +#define __NR_POSIX_SGI_reserved21 (__NR_POSIX + 314) +#define __NR_POSIX_SGI_reserved22 (__NR_POSIX + 315) +#define __NR_POSIX_SGI_reserved23 (__NR_POSIX + 316) +#define __NR_POSIX_SGI_reserved24 (__NR_POSIX + 317) +#define __NR_POSIX_SGI_reserved25 (__NR_POSIX + 318) +#define __NR_POSIX_SGI_reserved26 (__NR_POSIX + 319) + +#endif /* _ASM_RISCOS_SYSCALL_H */ diff --git a/include/asm-mips/semaphore-helper.h b/include/asm-mips/semaphore-helper.h index b6eb8e4f997e..ad49f94f31b5 100644 --- a/include/asm-mips/semaphore-helper.h +++ b/include/asm-mips/semaphore-helper.h @@ -1,11 +1,11 @@ -/* $Id: semaphore-helper.h,v 1.6 1999/10/20 21:10:58 ralf Exp $ - * +/* * SMP- and interrupt-safe semaphores helper functions. * - * (C) Copyright 1996 Linus Torvalds - * (C) Copyright 1999 Andrea Arcangeli - * (C) Copyright 1999 Ralf Baechle - * (C) Copyright 1999 Silicon Graphics, Inc. + * Copyright (C) 1996 Linus Torvalds + * Copyright (C) 1999 Andrea Arcangeli + * Copyright (C) 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) 2000 MIPS Technologies, Inc. */ #ifndef _ASM_SEMAPHORE_HELPER_H #define _ASM_SEMAPHORE_HELPER_H @@ -20,7 +20,7 @@ static inline void wake_one_more(struct semaphore * sem) atomic_inc(&sem->waking); } -#if !defined(CONFIG_CPU_HAS_LLSC) +#if !defined(CONFIG_CPU_HAS_LLSC) || defined(CONFIG_CPU_MIPS32) /* * It doesn't make sense, IMHO, to endlessly turn interrupts off and on again. @@ -75,6 +75,7 @@ static inline int waking_non_zero_trylock(struct semaphore *sem) ret = 0; } restore_flags(flags); + return ret; } @@ -92,7 +93,7 @@ waking_non_zero(struct semaphore *sem) "sc\t%0, %2\n\t" "beqz\t%0, 1b\n\t" "2:" - : "=r"(ret), "=r"(tmp), "=m"(__atomic_fool_gcc(&sem->waking)) + : "=r" (ret), "=r" (tmp), "=m" (sem->waking) : "0"(0)); return ret; @@ -133,29 +134,26 @@ waking_non_zero_interruptible(struct semaphore *sem, struct task_struct *tsk) { long ret, tmp; - __asm__ __volatile__(" - .set push - .set mips3 - .set noat -0: lld %1, %2 - li %0, 0 - sll $1, %1, 0 - blez $1, 1f - daddiu %1, %1, -1 - li %0, 1 - b 2f -1: - beqz %3, 2f - li %0, %4 - dli $1, 0x0000000100000000 - daddu %1, %1, $1 -2: - scd %1, %2 - beqz %1, 0b - - .set pop" - : "=&r"(ret), "=&r"(tmp), "=m"(*sem) - : "r"(signal_pending(tsk)), "i"(-EINTR)); + __asm__ __volatile__( + ".set\tpush\n\t" + ".set\tmips3\n\t" + ".set\tnoat\n" + "0:\tlld\t%1, %2\n\t" + "li\t%0, 0\n\t" + "sll\t$1, %1, 0\n\t" + "blez\t$1, 1f\n\t" + "daddiu\t%1, %1, -1\n\t" + "li\t%0, 1\n\t" + "b\t2f\n" + "1:\tbeqz\t%3, 2f\n\t" + "li\t%0, %4\n\t" + "dli\t$1, 0x0000000100000000\n\t" + "daddu\t%1, %1, $1\n" + "2:\tscd\t%1, %2\n\t" + "beqz\t%1, 0b\n\t" + ".set\tpop" + : "=&r" (ret), "=&r" (tmp), "=m" (*sem) + : "r" (signal_pending(tsk)), "i" (-EINTR)); return ret; } diff --git a/include/asm-mips/semaphore.h b/include/asm-mips/semaphore.h index baffb07ba8dc..4897792a1e09 100644 --- a/include/asm-mips/semaphore.h +++ b/include/asm-mips/semaphore.h @@ -1,5 +1,4 @@ -/* $Id: semaphore.h,v 1.12 1999/12/08 22:05:10 harald Exp $ - * +/* * SMP- and interrupt-safe semaphores.. * * This file is subject to the terms and conditions of the GNU General Public @@ -9,6 +8,7 @@ * (C) Copyright 1996 Linus Torvalds * (C) Copyright 1998, 1999, 2000 Ralf Baechle * (C) Copyright 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. */ #ifndef _ASM_SEMAPHORE_H #define _ASM_SEMAPHORE_H @@ -60,7 +60,7 @@ struct semaphore { #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) -extern inline void sema_init (struct semaphore *sem, int val) +static inline void sema_init (struct semaphore *sem, int val) { atomic_set(&sem->count, val); atomic_set(&sem->waking, 0); @@ -85,7 +85,7 @@ asmlinkage int __down_interruptible(struct semaphore * sem); asmlinkage int __down_trylock(struct semaphore * sem); asmlinkage void __up(struct semaphore * sem); -extern inline void down(struct semaphore * sem) +static inline void down(struct semaphore * sem) { #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); @@ -94,7 +94,7 @@ extern inline void down(struct semaphore * sem) __down(sem); } -extern inline int down_interruptible(struct semaphore * sem) +static inline int down_interruptible(struct semaphore * sem) { int ret = 0; @@ -106,9 +106,9 @@ extern inline int down_interruptible(struct semaphore * sem) return ret; } -#if !defined(CONFIG_CPU_HAS_LLSC) +#if !defined(CONFIG_CPU_HAS_LLSC) || defined(CONFIG_CPU_MIPS32) -extern inline int down_trylock(struct semaphore * sem) +static inline int down_trylock(struct semaphore * sem) { int ret = 0; if (atomic_dec_return(&sem->count) < 0) @@ -140,7 +140,7 @@ extern inline int down_trylock(struct semaphore * sem) * } * } */ -extern inline int down_trylock(struct semaphore * sem) +static inline int down_trylock(struct semaphore * sem) { long ret, tmp, tmp2, sub; @@ -148,29 +148,25 @@ extern inline int down_trylock(struct semaphore * sem) CHECK_MAGIC(sem->__magic); #endif - __asm__ __volatile__(" - .set mips3 - - 0: lld %1, %4 - dli %3, 0x0000000100000000 - dsubu %1, %3 - li %0, 0 - bgez %1, 2f - sll %2, %1, 0 - blez %2, 1f - daddiu %1, %1, -1 - b 2f - 1: - daddu %1, %1, %3 - li %0, 1 - 2: - scd %1, %4 - beqz %1, 0b - - .set mips0" - : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub) - : "m"(*sem) - : "memory"); + __asm__ __volatile__( + ".set\tmips3\t\t\t# down_trylock\n" + "0:\tlld\t%1, %4\n\t" + "dli\t%3, 0x0000000100000000\n\t" + "dsubu\t%1, %3\n\t" + "li\t%0, 0\n\t" + "bgez\t%1, 2f\n\t" + "sll\t%2, %1, 0\n\t" + "blez\t%2, 1f\n\t" + "daddiu\t%1, %1, -1\n\t" + "b\t2f\n\t" + "1:\tdaddu\t%1, %1, %3\n" + "li\t%0, 1\n" + "2:\tscd\t%1, %4\n\t" + "beqz\t%1, 0b\n\t" + ".set mips0" + : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub) + : "m"(*sem) + : "memory"); return ret; } @@ -181,7 +177,7 @@ extern inline int down_trylock(struct semaphore * sem) * Note! This is subtle. We jump to wake people up only if * the semaphore was negative (== somebody was waiting on it). */ -extern inline void up(struct semaphore * sem) +static inline void up(struct semaphore * sem) { #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); @@ -190,174 +186,4 @@ extern inline void up(struct semaphore * sem) __up(sem); } -/* - * rw mutexes (should that be mutices? =) -- throw rw spinlocks and - * semaphores together, and this is what we end up with... - * - * The lock is initialized to BIAS. This way, a writer subtracts BIAS ands - * gets 0 for the case of an uncontended lock. Readers decrement by 1 and - * see a positive value when uncontended, negative if there are writers - * waiting (in which case it goes to sleep). - * - * The value 0x01000000 supports up to 128 processors and lots of processes. - * BIAS must be chosen such that subtracting BIAS once per CPU will result - * in the int remaining negative. In terms of fairness, this should result - * in the lock flopping back and forth between readers and writers under - * heavy use. - * - * Once we start supporting machines with more than 128 CPUs, we should go - * for using a 64bit atomic type instead of 32bit as counter. We shall - * probably go for bias 0x80000000 then, so that single sethi can set it. - * */ - -#define RW_LOCK_BIAS 0x01000000 - -struct rw_semaphore { - atomic_t count; - /* bit 0 means read bias granted; - bit 1 means write bias granted. */ - unsigned long granted; /* pedant: long req'd for set_bit */ - wait_queue_head_t wait; - wait_queue_head_t write_bias_wait; -#if WAITQUEUE_DEBUG - long __magic; - atomic_t readers; - atomic_t writers; -#endif -}; - -#if WAITQUEUE_DEBUG -#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) -#else -#define __RWSEM_DEBUG_INIT /* */ -#endif - -#define __RWSEM_INITIALIZER(name,count) \ - { ATOMIC_INIT(count), 0, \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ - __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } - -#define __DECLARE_RWSEM_GENERIC(name,count) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name,count) - -#define DECLARE_RWSEM(name) \ - __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS) -#define DECLARE_RWSEM_READ_LOCKED(name) \ - __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS-1) -#define DECLARE_RWSEM_WRITE_LOCKED(name) \ - __DECLARE_RWSEM_GENERIC(name, 0) - -extern inline void init_rwsem(struct rw_semaphore *sem) -{ - atomic_set(&sem->count, RW_LOCK_BIAS); - sem->granted = 0; - init_waitqueue_head(&sem->wait); - init_waitqueue_head(&sem->write_bias_wait); -#if WAITQUEUE_DEBUG - sem->__magic = (long)&sem->__magic; - atomic_set(&sem->readers, 0); - atomic_set(&sem->writers, 0); -#endif -} - -/* The expensive part is outlined. */ -extern void __down_read(struct rw_semaphore *sem, int count); -extern void __down_write(struct rw_semaphore *sem, int count); -extern void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers); - -extern inline void down_read(struct rw_semaphore *sem) -{ - int count; - -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - count = atomic_dec_return(&sem->count); - if (count < 0) { - __down_read(sem, count); - } - mb(); - -#if WAITQUEUE_DEBUG - if (sem->granted & 2) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_inc(&sem->readers); -#endif -} - -extern inline void down_write(struct rw_semaphore *sem) -{ - int count; - -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif - - count = atomic_sub_return(RW_LOCK_BIAS, &sem->count); - if (count) { - __down_write(sem, count); - } - mb(); - -#if WAITQUEUE_DEBUG - if (atomic_read(&sem->writers)) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (sem->granted & 3) - BUG(); - atomic_inc(&sem->writers); -#endif -} - -/* When a reader does a release, the only significant case is when - there was a writer waiting, and we've bumped the count to 0: we must - wake the writer up. */ - -extern inline void up_read(struct rw_semaphore *sem) -{ -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); - if (sem->granted & 2) - BUG(); - if (atomic_read(&sem->writers)) - BUG(); - atomic_dec(&sem->readers); -#endif - - mb(); - if (atomic_inc_return(&sem->count) == 0) - __rwsem_wake(sem, 0); -} - -/* - * Releasing the writer is easy -- just release it and wake up any sleepers. - */ -extern inline void up_write(struct rw_semaphore *sem) -{ - int count; - -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); - if (sem->granted & 3) - BUG(); - if (atomic_read(&sem->readers)) - BUG(); - if (atomic_read(&sem->writers) != 1) - BUG(); - atomic_dec(&sem->writers); -#endif - - mb(); - count = atomic_add_return(RW_LOCK_BIAS, &sem->count); - if (count - RW_LOCK_BIAS < 0 && count >= 0) { - /* Only do the wake if we're no longer negative. */ - __rwsem_wake(sem, count); - } -} - #endif /* _ASM_SEMAPHORE_H */ diff --git a/include/asm-mips/serial.h b/include/asm-mips/serial.h index f255684b4e8b..346b321e4cfc 100644 --- a/include/asm-mips/serial.h +++ b/include/asm-mips/serial.h @@ -1,5 +1,4 @@ -/* $Id: serial.h,v 1.9 2000/02/16 01:45:55 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -76,6 +75,81 @@ #define JAZZ_SERIAL_PORT_DEFNS #endif +#ifdef CONFIG_MIPS_ATLAS +#include <asm/mips-boards/atlas.h> +#include <asm/mips-boards/atlasint.h> +#define ATLAS_SERIAL_PORT_DEFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, ATLAS_BASE_BAUD, ATLAS_UART_REGS_BASE, ATLASINT_UART, STD_COM_FLAGS }, /* ttyS0 */ +#else +#define ATLAS_SERIAL_PORT_DEFNS +#endif + +/* + * Both Galileo boards have the same UART mappings. + */ +#if defined (CONFIG_MIPS_EV96100) || defined (CONFIG_MIPS_EV64120) +#include <asm/galileo-boards/ev96100.h> +#include <asm/galileo-boards/ev96100int.h> +#define EV96100_SERIAL_PORT_DEFNS \ + { baud_base: EV96100_BASE_BAUD, port: EV96100_UART0_REGS_BASE, \ + irq: EV96100INT_UART_0, flags: STD_COM_FLAGS, type: 0x3, \ + iomem_base: EV96100_UART0_REGS_BASE }, \ + { baud_base: EV96100_BASE_BAUD, port: EV96100_UART1_REGS_BASE, \ + irq: EV96100INT_UART_0, flags: STD_COM_FLAGS, type: 0x3, \ + iomem_base: EV96100_UART1_REGS_BASE }, +#else +#define EV96100_SERIAL_PORT_DEFNS +#endif + +#ifdef CONFIG_MIPS_ITE8172 +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_int.h> +#include <asm/it8712.h> +#define ITE_SERIAL_PORT_DEFNS \ + { baud_base: BASE_BAUD, port: (IT8172_PCI_IO_BASE + IT_UART_BASE), \ + irq: IT8172_UART_IRQ, flags: STD_COM_FLAGS, type: 0x3 }, \ + { baud_base: (24000000/(16*13)), port: (IT8172_PCI_IO_BASE + IT8712_UART1_PORT), \ + irq: IT8172_SERIRQ_4, flags: STD_COM_FLAGS, type: 0x3 }, \ + /* Smart Card Reader 0 */ \ + { baud_base: BASE_BAUD, port: (IT8172_PCI_IO_BASE + IT_SCR0_BASE), \ + irq: IT8172_SCR0_IRQ, flags: STD_COM_FLAGS, type: 0x3 }, \ + /* Smart Card Reader 1 */ \ + { baud_base: BASE_BAUD, port: (IT8172_PCI_IO_BASE + IT_SCR1_BASE), \ + irq: IT8172_SCR1_IRQ, flags: STD_COM_FLAGS, type: 0x3 }, +#else +#define ITE_SERIAL_PORT_DEFNS +#endif + +#ifdef CONFIG_MIPS_IVR +#include <asm/it8172/it8172.h> +#include <asm/it8172/it8172_int.h> +#define IVR_SERIAL_PORT_DEFNS \ + { baud_base: BASE_BAUD, port: (IT8172_PCI_IO_BASE + IT_UART_BASE), \ + irq: IT8172_UART_IRQ, flags: STD_COM_FLAGS, type: 0x3 }, \ + /* Smart Card Reader 1 */ \ + { baud_base: BASE_BAUD, port: (IT8172_PCI_IO_BASE + IT_SCR1_BASE), \ + irq: IT8172_SCR1_IRQ, flags: STD_COM_FLAGS, type: 0x3 }, +#else +#define IVR_SERIAL_PORT_DEFNS +#endif + +#ifdef CONFIG_AU1000_UART +#include <asm/au1000.h> +#define AU1000_SERIAL_PORT_DEFNS \ + { baud_base: 0, port: UART0_ADDR, irq: AU1000_UART0_INT, \ + flags: STD_COM_FLAGS, type: 1 }, \ + { baud_base: 0, port: UART1_ADDR, irq: AU1000_UART1_INT, \ + flags: STD_COM_FLAGS, type: 1 }, \ + { baud_base: 0, port: UART2_ADDR, irq: AU1000_UART2_INT, \ + flags: STD_COM_FLAGS, type: 1 }, \ + { baud_base: 0, port: UART3_ADDR, irq: AU1000_UART3_INT, \ + flags: STD_COM_FLAGS, type: 1 }, +#else +#define AU1000_SERIAL_PORT_DEFNS +#endif + +#ifdef CONFIG_HAVE_STD_PC_SERIAL_PORT #define STD_SERIAL_PORT_DEFNS \ /* UART CLK PORT IRQ FLAGS */ \ { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \ @@ -83,7 +157,6 @@ { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \ { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */ - #ifdef CONFIG_SERIAL_MANY_PORTS #define EXTRA_SERIAL_PORT_DEFNS \ { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ \ @@ -96,8 +169,8 @@ { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */ \ { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */ \ { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */ \ - { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare) */ \ - { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare) */ \ + { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare) */ \ + { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare) */ \ { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */ \ { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */ \ { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */ \ @@ -114,9 +187,14 @@ { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */ \ { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */ \ { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */ -#else +#else /* CONFIG_SERIAL_MANY_PORTS */ #define EXTRA_SERIAL_PORT_DEFNS -#endif +#endif /* CONFIG_SERIAL_MANY_PORTS */ + +#else /* CONFIG_HAVE_STD_PC_SERIAL_PORTS */ +#define STD_SERIAL_PORT_DEFNS +#define EXTRA_SERIAL_PORT_DEFNS +#endif /* CONFIG_HAVE_STD_PC_SERIAL_PORTS */ /* You can have up to four HUB6's in the system, but I've only * included two cards here for a total of twelve ports. @@ -151,8 +229,44 @@ #define MCA_SERIAL_PORT_DFNS #endif +#ifdef CONFIG_MOMENCO_OCELOT +/* Ordinary NS16552 duart with a 20MHz crystal. */ +#define OCELOT_BASE_BAUD ( 20000000 / 16 ) + +#define OCELOT_SERIAL1_IRQ 4 +#define OCELOT_SERIAL1_BASE 0xe0001020 + +#define _OCELOT_SERIAL_INIT(int, base) \ + { baud_base: OCELOT_BASE_BAUD, irq: int, flags: STD_COM_FLAGS, \ + iomem_base: (u8 *) base, iomem_reg_shift: 2, \ + io_type: SERIAL_IO_MEM } +#define MOMENCO_OCELOT_SERIAL_PORT_DEFNS \ + _OCELOT_SERIAL_INIT(OCELOT_SERIAL1_IRQ, OCELOT_SERIAL1_BASE) +#else +#define MOMENCO_OCELOT_SERIAL_PORT_DEFNS +#endif + +#ifdef CONFIG_DDB5477 +#define DDB5477_SERIAL_PORT_DEFNS \ + { baud_base: BASE_BAUD, irq: 12, flags: STD_COM_FLAGS, \ + iomem_base: (u8*)0xbfa04200, iomem_reg_shift: 3, \ + io_type: SERIAL_IO_MEM},\ + { baud_base: BASE_BAUD, irq: 28, flags: STD_COM_FLAGS, \ + iomem_base: (u8*)0xbfa04240, iomem_reg_shift: 3, \ + io_type: SERIAL_IO_MEM}, +#else +#define DDB5477_SERIAL_PORT_DEFNS +#endif + #define SERIAL_PORT_DFNS \ + IVR_SERIAL_PORT_DEFNS \ + ITE_SERIAL_PORT_DEFNS \ + ATLAS_SERIAL_PORT_DEFNS \ + EV96100_SERIAL_PORT_DEFNS \ JAZZ_SERIAL_PORT_DEFNS \ STD_SERIAL_PORT_DEFNS \ EXTRA_SERIAL_PORT_DEFNS \ - HUB6_SERIAL_PORT_DFNS + HUB6_SERIAL_PORT_DFNS \ + MOMENCO_OCELOT_SERIAL_PORT_DEFNS\ + AU1000_SERIAL_PORT_DEFNS \ + DDB5477_SERIAL_PORT_DEFNS diff --git a/include/asm-mips/sgi/sgint23.h b/include/asm-mips/sgi/sgint23.h index d851d2f3011a..0641c133c626 100644 --- a/include/asm-mips/sgi/sgint23.h +++ b/include/asm-mips/sgi/sgint23.h @@ -1,5 +1,4 @@ -/* $Id: sgint23.h,v 1.4 1999/09/28 21:02:12 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -7,6 +6,7 @@ * sgint23.h: Defines for the SGI INT2 and INT3 chipsets. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 98, 1999, 2000 Ralf Baechle * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - INT2 corrections */ #ifndef _ASM_SGI_SGINT23_H @@ -25,20 +25,8 @@ #define SGINT_HPCDMA 41 /* INDY has 11 HPCDMA irq _sources_ */ #define SGINT_END 52 /* End of 'spaces' */ -/* Individual interrupt definitions for the INDY and Indigo2 - */ - -#define SGI_WD93_0_IRQ SGINT_LOCAL0 + 1 /* 1st onboard WD93 */ -#define SGI_WD93_1_IRQ SGINT_LOCAL0 + 2 /* 2nd onboard WD93 */ -#define SGI_ENET_IRQ SGINT_LOCAL0 + 3 /* onboard ethernet */ - -#define SGI_PANEL_IRQ SGINT_LOCAL1 + 1 /* front panel */ - -#define SGI_EISA_IRQ SGINT_LOCAL2 + 3 /* EISA interrupts */ -#define SGI_KEYBOARD_IRQ SGINT_LOCAL2 + 4 /* keyboard */ -#define SGI_SERIAL_IRQ SGINT_LOCAL2 + 5 /* onboard serial */ - -/* Individual interrupt definitions for the INDY and Indigo2 +/* + * Individual interrupt definitions for the INDY and Indigo2 */ #define SGI_WD93_0_IRQ SGINT_LOCAL0 + 1 /* 1st onboard WD93 */ @@ -215,4 +203,4 @@ extern volatile unsigned char *ioc_tclear; extern void sgint_init(void); extern void indy_timer_init(void); -#endif /* !(_ASM_SGINT23_H) */ +#endif /* _ASM_SGI_SGINT23_H */ diff --git a/include/asm-mips/sgialib.h b/include/asm-mips/sgialib.h index 8a9e2f49e1bc..f53389c5b9dd 100644 --- a/include/asm-mips/sgialib.h +++ b/include/asm-mips/sgialib.h @@ -1,9 +1,8 @@ -/* $Id: sgialib.h,v 1.5 2000/03/19 01:28:58 ralf Exp $ +/* * sgialib.h: SGI ARCS firmware interface library for the Linux kernel. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) */ - #ifndef _ASM_SGIALIB_H #define _ASM_SGIALIB_H @@ -21,7 +20,7 @@ extern int prom_flags; * Init the PROM library and it's internal data structures. Called * at boot time from head.S before start_kernel is invoked. */ -extern int prom_init(int argc, char **argv, char **envp, int *prom_vec); +extern void prom_init(int argc, char **argv, char **envp, int *prom_vec); /* Simple char-by-char console I/O. */ extern void prom_putchar(char c); @@ -30,28 +29,12 @@ extern char prom_getchar(void); /* Generic printf() using ARCS console I/O. */ extern void prom_printf(char *fmt, ...); -/* Memory descriptor management. */ -#define PROM_MAX_PMEMBLOCKS 32 -struct prom_pmemblock { - unsigned long base; /* Within KSEG0. */ - unsigned int size; /* In bytes. */ - unsigned int type; /* free or prom memory */ -}; - -/* Get next memory descriptor after CURR, returns first descriptor - * in chain is CURR is NULL. - */ -extern struct linux_mdesc *prom_getmdesc(struct linux_mdesc *curr); #define PROM_NULL_MDESC ((struct linux_mdesc *) 0) /* Called by prom_init to setup the physical memory pmemblock * array. */ extern void prom_meminit(void); -extern void prom_fixup_mem_map(unsigned long start_mem, unsigned long end_mem); - -/* Returns pointer to PROM physical memory block array. */ -extern struct prom_pmemblock *prom_getpblock_array(void); /* PROM device tree library routines. */ #define PROM_NULL_COMPONENT ((pcomponent *) 0) @@ -81,9 +64,9 @@ extern pcomponent *prom_componentbypath(char *path); */ extern void prom_identify_arch(void); -/* Environemt variable routines. */ +/* Environment variable routines. */ extern PCHAR ArcGetEnvironmentVariable(CHAR *name); -extern LONG SetEnvironmentVariable(PCHAR name, PCHAR value); +extern LONG ArcSetEnvironmentVariable(PCHAR name, PCHAR value); /* ARCS command line acquisition and parsing. */ extern char *prom_getcmdline(void); @@ -115,7 +98,7 @@ extern void prom_halt(void) __attribute__((noreturn)); extern void prom_powerdown(void) __attribute__((noreturn)); extern void prom_restart(void) __attribute__((noreturn)); extern void prom_reboot(void) __attribute__((noreturn)); -extern void prom_imode(void) __attribute__((noreturn)); +extern void ArcEnterInteractiveMode(void) __attribute__((noreturn)); extern long prom_cfgsave(void); extern struct linux_sysid *prom_getsysid(void); extern void prom_cacheflush(void); diff --git a/include/asm-mips/shmbuf.h b/include/asm-mips/shmbuf.h index 077cfced31bb..37274d6d1e74 100644 --- a/include/asm-mips/shmbuf.h +++ b/include/asm-mips/shmbuf.h @@ -7,7 +7,7 @@ * between kernel and user space. * * Pad space is left for: - * - 2 miscellaneous 64-bit values + * - 2 miscellaneous 32-bit values */ struct shmid64_ds { diff --git a/include/asm-mips/smp.h b/include/asm-mips/smp.h index 601826429bbe..1bfcf41e09c2 100644 --- a/include/asm-mips/smp.h +++ b/include/asm-mips/smp.h @@ -1,6 +1,37 @@ #ifndef __ASM_MIPS_SMP_H #define __ASM_MIPS_SMP_H +#include <linux/config.h> + +#ifdef CONFIG_SMP + +#include <asm/spinlock.h> +#include <asm/atomic.h> +#include <asm/current.h> + + +/* Mappings are straight across. If we want + to add support for disabling cpus and such, + we'll have to do what the mips64 port does here */ #define cpu_logical_map(cpu) (cpu) +#define cpu_number_map(cpu) (cpu) + +#define smp_processor_id() (current->processor) + + +/* I've no idea what the real meaning of this is */ +#define PROC_CHANGE_PENALTY 20 + +#define NO_PROC_ID (-1) + +struct smp_fn_call_struct { + spinlock_t lock; + atomic_t finished; + void (*fn)(void *); + void *data; +}; + +extern struct smp_fn_call_struct smp_fn_call; +#endif /* CONFIG_SMP */ #endif /* __ASM_MIPS_SMP_H */ diff --git a/include/asm-mips/sni.h b/include/asm-mips/sni.h index 1e2391ddb0e4..fb961478e07d 100644 --- a/include/asm-mips/sni.h +++ b/include/asm-mips/sni.h @@ -30,6 +30,14 @@ #define PCIMT_ERRADDR 0xbfff0040 #define PCIMT_SYNDROME 0xbfff0048 #define PCIMT_ITPEND 0xbfff0050 +#define IT_INT2 0x01 +#define IT_INTD 0x02 +#define IT_INTC 0x04 +#define IT_INTB 0x08 +#define IT_INTA 0x10 +#define IT_EISA 0x20 +#define IT_SCSI 0x40 +#define IT_ETH 0x80 #define PCIMT_IRQSEL 0xbfff0058 #define PCIMT_TESTMEM 0xbfff0060 #define PCIMT_ECCREG 0xbfff0068 @@ -73,16 +81,18 @@ * to the other interrupts generated by ASIC PCI. */ #define PCIMT_KEYBOARD_IRQ 1 -#define PCIMT_IRQ_ETHERNET 16 -#define PCIMT_IRQ_TEMPERATURE 17 -#define PCIMT_IRQ_EISA_NMI 18 -#define PCIMT_IRQ_POWER_OFF 19 -#define PCIMT_IRQ_BUTTON 20 -#define PCIMT_IRQ_INTA 21 -#define PCIMT_IRQ_INTB 22 -#define PCIMT_IRQ_INTC 23 -#define PCIMT_IRQ_INTD 24 -#define PCIMT_IRQ_SCSI 25 +#define PCIMT_IRQ_INT2 16 /* What is that? */ +#define PCIMT_IRQ_INTD 17 +#define PCIMT_IRQ_INTC 18 +#define PCIMT_IRQ_INTB 19 +#define PCIMT_IRQ_INTA 20 +#define PCIMT_IRQ_EISA 21 +#define PCIMT_IRQ_SCSI 22 +#define PCIMT_IRQ_ETHERNET 23 +#define PCIMT_IRQ_TEMPERATURE 24 +#define PCIMT_IRQ_EISA_NMI 25 +#define PCIMT_IRQ_POWER_OFF 26 +#define PCIMT_IRQ_BUTTON 27 /* * Base address for the mapped 16mb EISA bus segment. diff --git a/include/asm-mips/socket.h b/include/asm-mips/socket.h index 201317fb6445..b8a570fa0af9 100644 --- a/include/asm-mips/socket.h +++ b/include/asm-mips/socket.h @@ -33,7 +33,7 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ #define SO_RCVLOWAT 0x1004 /* receive low-water mark */ #define SO_SNDTIMEO 0x1005 /* send timeout */ #define SO_RCVTIMEO 0x1006 /* receive timeout */ -#define SO_ACCEPTCONN 0x1007 +#define SO_ACCEPTCONN 0x1009 /* linux-specific, might as well be the same as on i386 */ #define SO_NO_CHECK 11 diff --git a/include/asm-mips/spinlock.h b/include/asm-mips/spinlock.h index 724d105200fc..61ebfa6603eb 100644 --- a/include/asm-mips/spinlock.h +++ b/include/asm-mips/spinlock.h @@ -1,5 +1,4 @@ -/* $Id: spinlock.h,v 1.8 2000/01/23 21:15:52 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -22,6 +21,9 @@ typedef struct { #define spin_lock_init(x) do { (x)->lock = 0; } while(0); +#define spin_is_locked(x) ((x)->lock != 0) +#define spin_unlock_wait(x) ({ do { barrier(); } while ((x)->lock); }) + /* * Simple spin lock operations. There are two variants, one clears IRQ's * on the local processor, one does not. @@ -29,9 +31,6 @@ typedef struct { * We make no fairness assumptions. They have a cost. */ -typedef struct { unsigned long a[100]; } __dummy_lock_t; -#define __dummy_lock(lock) (*(__dummy_lock_t *)(lock)) - static inline void spin_lock(spinlock_t *lock) { unsigned int tmp; @@ -45,8 +44,8 @@ static inline void spin_lock(spinlock_t *lock) "beqz\t%1, 1b\n\t" " sync\n\t" ".set\treorder" - : "=o" (__dummy_lock(lock)), "=&r" (tmp) - : "o" (__dummy_lock(lock)) + : "=o" (lock->lock), "=&r" (tmp) + : "o" (lock->lock) : "memory"); } @@ -57,8 +56,8 @@ static inline void spin_unlock(spinlock_t *lock) "sync\n\t" "sw\t$0, %0\n\t" ".set\treorder" - : "=o" (__dummy_lock(lock)) - : "o" (__dummy_lock(lock)) + : "=o" (lock->lock) + : "o" (lock->lock) : "memory"); } @@ -92,8 +91,8 @@ static inline void read_lock(rwlock_t *rw) "beqz\t%1, 1b\n\t" " sync\n\t" ".set\treorder" - : "=o" (__dummy_lock(rw)), "=&r" (tmp) - : "o" (__dummy_lock(rw)) + : "=o" (rw->lock), "=&r" (tmp) + : "o" (rw->lock) : "memory"); } @@ -111,8 +110,8 @@ static inline void read_unlock(rwlock_t *rw) "sc\t%1, %0\n\t" "beqz\t%1, 1b\n\t" ".set\treorder" - : "=o" (__dummy_lock(rw)), "=&r" (tmp) - : "o" (__dummy_lock(rw)) + : "=o" (rw->lock), "=&r" (tmp) + : "o" (rw->lock) : "memory"); } @@ -129,8 +128,8 @@ static inline void write_lock(rwlock_t *rw) "beqz\t%1, 1b\n\t" " sync\n\t" ".set\treorder" - : "=o" (__dummy_lock(rw)), "=&r" (tmp) - : "o" (__dummy_lock(rw)) + : "=o" (rw->lock), "=&r" (tmp) + : "o" (rw->lock) : "memory"); } @@ -141,8 +140,8 @@ static inline void write_unlock(rwlock_t *rw) "sync\n\t" "sw\t$0, %0\n\t" ".set\treorder" - : "=o" (__dummy_lock(rw)) - : "o" (__dummy_lock(rw)) + : "=o" (rw->lock) + : "o" (rw->lock) : "memory"); } diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h index 490724b21a66..d46cecef9afc 100644 --- a/include/asm-mips/stackframe.h +++ b/include/asm-mips/stackframe.h @@ -1,13 +1,17 @@ /* - * include/asm-mips/stackframe.h + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * - * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Paul M. Antoine. - * - * $Id: stackframe.h,v 1.10 1999/08/13 17:07:27 harald Exp $ + * Copyright (C) 1994, 1995, 1996, 2001 Ralf Baechle + * Copyright (C) 1994, 1995, 1996 Paul M. Antoine. */ -#ifndef __ASM_MIPS_STACKFRAME_H -#define __ASM_MIPS_STACKFRAME_H +#ifndef __ASM_STACKFRAME_H +#define __ASM_STACKFRAME_H +#include <asm/addrspace.h> +#include <asm/mipsregs.h> +#include <asm/processor.h> #include <asm/asm.h> #include <asm/offset.h> #include <linux/config.h> @@ -47,20 +51,45 @@ #define __str2(x) #x #define __str(x) __str2(x) -#define save_static(frame) \ - __asm__ __volatile__( \ - "sw\t$16,"__str(PT_R16)"(%0)\n\t" \ - "sw\t$17,"__str(PT_R17)"(%0)\n\t" \ - "sw\t$18,"__str(PT_R18)"(%0)\n\t" \ - "sw\t$19,"__str(PT_R19)"(%0)\n\t" \ - "sw\t$20,"__str(PT_R20)"(%0)\n\t" \ - "sw\t$21,"__str(PT_R21)"(%0)\n\t" \ - "sw\t$22,"__str(PT_R22)"(%0)\n\t" \ - "sw\t$23,"__str(PT_R23)"(%0)\n\t" \ - "sw\t$30,"__str(PT_R30)"(%0)\n\t" \ - : /* No outputs */ \ - : "r" (frame)) +#define save_static_function(symbol) \ +__asm__ ( \ + ".globl\t" #symbol "\n\t" \ + ".align\t2\n\t" \ + ".type\t" #symbol ", @function\n\t" \ + ".ent\t" #symbol ", 0\n" \ + #symbol":\n\t" \ + ".frame\t$29, 0, $31\n\t" \ + "sw\t$16,"__str(PT_R16)"($29)\t\t\t# save_static_function\n\t" \ + "sw\t$17,"__str(PT_R17)"($29)\n\t" \ + "sw\t$18,"__str(PT_R18)"($29)\n\t" \ + "sw\t$19,"__str(PT_R19)"($29)\n\t" \ + "sw\t$20,"__str(PT_R20)"($29)\n\t" \ + "sw\t$21,"__str(PT_R21)"($29)\n\t" \ + "sw\t$22,"__str(PT_R22)"($29)\n\t" \ + "sw\t$23,"__str(PT_R23)"($29)\n\t" \ + "sw\t$30,"__str(PT_R30)"($29)\n\t" \ + ".end\t" #symbol "\n\t" \ + ".size\t" #symbol",. - " #symbol) + +/* Used in declaration of save_static functions. */ +#define static_unused static __attribute__((unused)) + + +#ifdef CONFIG_SMP +# define GET_SAVED_SP \ + mfc0 k0, CP0_CONTEXT; \ + lui k1, %hi(kernelsp); \ + srl k0, k0, 23; \ + sll k0, k0, 2; \ + addu k1, k0; \ + lw k1, %lo(kernelsp)(k1); +#else +# define GET_SAVED_SP \ + lui k1, %hi(kernelsp); \ + lw k1, %lo(kernelsp)(k1); +#endif + #define SAVE_SOME \ .set push; \ .set reorder; \ @@ -71,13 +100,12 @@ move k1, sp; \ .set reorder; \ /* Called from user mode, new stack. */ \ - lui k1, %hi(kernelsp); \ - lw k1, %lo(kernelsp)(k1); \ + GET_SAVED_SP \ 8: \ move k0, sp; \ subu sp, k1, PT_SIZE; \ sw k0, PT_R29(sp); \ - sw $3, PT_R3(sp); \ + sw $3, PT_R3(sp); \ sw $0, PT_R0(sp); \ mfc0 v1, CP0_STATUS; \ sw $2, PT_R2(sp); \ @@ -208,6 +236,16 @@ #endif +#define RESTORE_SP \ + lw sp, PT_R29(sp); \ + +#define RESTORE_ALL \ + RESTORE_SOME; \ + RESTORE_AT; \ + RESTORE_TEMP; \ + RESTORE_STATIC; \ + RESTORE_SP + #define RESTORE_ALL_AND_RET \ RESTORE_SOME; \ RESTORE_AT; \ @@ -215,6 +253,7 @@ RESTORE_STATIC; \ RESTORE_SP_AND_RET + /* * Move to kernel mode and disable interrupts. * Set cp0 enable bit as sign that we're running on the kernel stack @@ -248,4 +287,4 @@ xori t0,0x1e; \ mtc0 t0,CP0_STATUS -#endif /* __ASM_MIPS_STACKFRAME_H */ +#endif /* __ASM_STACKFRAME_H */ diff --git a/include/asm-mips/stat.h b/include/asm-mips/stat.h index e8892d3da493..f3f49a4ae386 100644 --- a/include/asm-mips/stat.h +++ b/include/asm-mips/stat.h @@ -17,8 +17,7 @@ struct __old_kernel_stat { unsigned int st_ctime, st_res3; unsigned int st_blksize; int st_blocks; - unsigned int st_flags; - unsigned int st_gen; + unsigned int st_unused0[2]; }; struct stat { @@ -45,11 +44,7 @@ struct stat { long reserved2; long st_blksize; long st_blocks; - char st_fstype[16]; /* Filesystem type name */ - long st_pad4[8]; - /* Linux specific fields */ - unsigned int st_flags; - unsigned int st_gen; + long st_pad4[14]; }; /* @@ -61,25 +56,36 @@ struct stat { struct stat64 { unsigned long st_dev; unsigned long st_pad0[3]; /* Reserved for st_dev expansion */ - ino_t st_ino; + + unsigned long long st_ino; + mode_t st_mode; nlink_t st_nlink; + uid_t st_uid; gid_t st_gid; + unsigned long st_rdev; unsigned long st_pad1[3]; /* Reserved for st_rdev expansion */ + long long st_size; + /* * Actually this should be timestruc_t st_atime, st_mtime and st_ctime * but we don't have it under Linux. */ time_t st_atime; unsigned long reserved0; /* Reserved for st_atime expansion */ + time_t st_mtime; - unsigned long reserved1; /* Reserved for st_atime expansion */ + unsigned long reserved1; /* Reserved for st_mtime expansion */ + time_t st_ctime; - unsigned long reserved2; /* Reserved for st_atime expansion */ + unsigned long reserved2; /* Reserved for st_ctime expansion */ + unsigned long st_blksize; + unsigned long st_pad2; + long long st_blocks; }; diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h index c057c0925506..df0dac9c9d35 100644 --- a/include/asm-mips/system.h +++ b/include/asm-mips/system.h @@ -1,5 +1,4 @@ -/* $Id: system.h,v 1.20 1999/12/06 23:13:21 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -7,6 +6,12 @@ * Copyright (C) 1994 - 1999 by Ralf Baechle * Copyright (C) 1996 by Paul M. Antoine * Copyright (C) 1994 - 1999 by Ralf Baechle + * + * Changed set_except_vector declaration to allow return of previous + * vector address value - necessary for "borrowing" vectors. + * + * Kevin D. Kissell, kevink@mips.org and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. */ #ifndef _ASM_SYSTEM_H #define _ASM_SYSTEM_H @@ -61,65 +66,76 @@ __cli(void) : "$1", "memory"); } -#define __save_flags(x) \ -__asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set\treorder\n\t" \ - "mfc0\t%0,$12\n\t" \ - ".set\tpop\n\t" \ - : "=r" (x) \ - : /* no inputs */ \ - : "memory") +#define __save_flags(x) \ +__asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\treorder\n\t" \ + "mfc0\t%0,$12\n\t" \ + ".set\tpop\n\t" \ + : "=r" (x)) -#define __save_and_cli(x) \ -__asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set\treorder\n\t" \ - ".set\tnoat\n\t" \ - "mfc0\t%0,$12\n\t" \ - "ori\t$1,%0,1\n\t" \ - "xori\t$1,1\n\t" \ - ".set\tnoreorder\n\t" \ - "mtc0\t$1,$12\n\t" \ - "nop\n\t" \ - "nop\n\t" \ - "nop\n\t" \ - ".set\tpop\n\t" \ - : "=r" (x) \ - : /* no inputs */ \ +#define __save_and_cli(x) \ +__asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\treorder\n\t" \ + ".set\tnoat\n\t" \ + "mfc0\t%0,$12\n\t" \ + "ori\t$1,%0,1\n\t" \ + "xori\t$1,1\n\t" \ + ".set\tnoreorder\n\t" \ + "mtc0\t$1,$12\n\t" \ + "nop\n\t" \ + "nop\n\t" \ + "nop\n\t" \ + ".set\tpop\n\t" \ + : "=r" (x) \ + : /* no inputs */ \ : "$1", "memory") -extern void __inline__ -__restore_flags(int flags) -{ - __asm__ __volatile__( - ".set\tpush\n\t" - ".set\treorder\n\t" - "mfc0\t$8,$12\n\t" - "li\t$9,0xff00\n\t" - "and\t$8,$9\n\t" - "nor\t$9,$0,$9\n\t" - "and\t%0,$9\n\t" - "or\t%0,$8\n\t" - ".set\tnoreorder\n\t" - "mtc0\t%0,$12\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" - ".set\tpop\n\t" - : - : "r" (flags) - : "$8", "$9", "memory"); -} +#define __restore_flags(flags) \ +do { \ + unsigned long __tmp1; \ + \ + __asm__ __volatile__( \ + ".set\tnoreorder\t\t\t# __restore_flags\n\t" \ + ".set\tnoat\n\t" \ + "mfc0\t$1, $12\n\t" \ + "andi\t%0, 1\n\t" \ + "ori\t$1, 1\n\t" \ + "xori\t$1, 1\n\t" \ + "or\t%0, $1\n\t" \ + "mtc0\t%0, $12\n\t" \ + "nop\n\t" \ + "nop\n\t" \ + "nop\n\t" \ + ".set\tat\n\t" \ + ".set\treorder" \ + : "=r" (__tmp1) \ + : "0" (flags) \ + : "$1", "memory"); \ +} while(0) -/* - * Non-SMP versions ... - */ -#define sti() __sti() -#define cli() __cli() -#define save_flags(x) __save_flags(x) -#define save_and_cli(x) __save_and_cli(x) -#define restore_flags(x) __restore_flags(x) +#ifdef CONFIG_SMP + +extern void __global_sti(void); +extern void __global_cli(void); +extern unsigned long __global_save_flags(void); +extern void __global_restore_flags(unsigned long); +# define sti() __global_sti() +# define cli() __global_cli() +# define save_flags(x) do { x = __global_save_flags(); } while (0) +# define restore_flags(x) __global_restore_flags(x) +# define save_and_cli(x) do { save_flags(x); cli(); } while(0) + +#else /* Single processor */ + +# define sti() __sti() +# define cli() __cli() +# define save_flags(x) __save_flags(x) +# define save_and_cli(x) __save_and_cli(x) +# define restore_flags(x) __restore_flags(x) + +#endif /* SMP */ /* For spinlocks etc */ #define local_irq_save(x) __save_and_cli(x); @@ -131,11 +147,14 @@ __restore_flags(int flags) * These are probably defined overly paranoid ... */ #ifdef CONFIG_CPU_HAS_WB + #include <asm/wbflush.h> -#define rmb() -#define wmb() wbflush() -#define mb() wbflush() -#else +#define rmb() do { } while(0) +#define wmb() wbflush() +#define mb() wbflush() + +#else /* CONFIG_CPU_HAS_WB */ + #define mb() \ __asm__ __volatile__( \ "# prevent instructions being moved around\n\t" \ @@ -148,6 +167,17 @@ __asm__ __volatile__( \ : "memory") #define rmb() mb() #define wmb() mb() + +#endif /* CONFIG_CPU_HAS_WB */ + +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#else +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() #endif #define set_mb(var, value) \ @@ -180,17 +210,17 @@ extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val) unsigned long dummy; __asm__ __volatile__( - ".set\tnoreorder\n\t" + ".set\tnoreorder\t\t\t# xchg_u32\n\t" ".set\tnoat\n\t" - "ll\t%0,(%1)\n" - "1:\tmove\t$1,%2\n\t" - "sc\t$1,(%1)\n\t" - "beqzl\t$1,1b\n\t" - "ll\t%0,(%1)\n\t" + "ll\t%0, %3\n" + "1:\tmove\t$1, %2\n\t" + "sc\t$1, %1\n\t" + "beqzl\t$1, 1b\n\t" + " ll\t%0, %3\n\t" ".set\tat\n\t" ".set\treorder" - : "=r" (val), "=r" (m), "=r" (dummy) - : "1" (m), "2" (val) + : "=r" (val), "=o" (*m), "=r" (dummy) + : "o" (*m), "2" (val) : "memory"); return val; @@ -207,64 +237,25 @@ extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val) #endif /* Processor-dependent optimization */ } -/* - * Only used for 64 bit kernel. - */ -extern __inline__ unsigned long xchg_u64(volatile long * m, unsigned long val) -{ - unsigned long dummy; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - "lld\t%0,(%1)\n" - "1:\tmove\t$1,%2\n\t" - "scd\t$1,(%1)\n\t" - "beqzl\t$1,1b\n\t" - "lld\t%0,(%1)\n\t" - ".set\tat\n\t" - ".set\treorder" - : "=r" (val), "=r" (m), "=r" (dummy) - : "1" (m), "2" (val) - : "memory"); - - return val; -} - #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) #define tas(ptr) (xchg((ptr),1)) -/* - * This function doesn't exist, so you'll get a linker error - * if something tries to do an invalid xchg(). - * - * This only works if the compiler isn't horribly bad at optimizing. - * gcc-2.5.8 reportedly can't handle this, but I define that one to - * be dead anyway. - */ -extern void __xchg_called_with_bad_pointer(void); - -static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr, int size) +static __inline__ unsigned long +__xchg(unsigned long x, volatile void * ptr, int size) { switch (size) { case 4: return xchg_u32(ptr, x); -#if defined(__mips64) - case 8: - return xchg_u64(ptr, x); -#endif } - __xchg_called_with_bad_pointer(); return x; } -extern void set_except_vector(int n, void *addr); +extern void *set_except_vector(int n, void *addr); extern void __die(const char *, struct pt_regs *, const char *where, unsigned long line) __attribute__((noreturn)); extern void __die_if_kernel(const char *, struct pt_regs *, const char *where, unsigned long line); -extern int abs(int); #define die(msg, regs) \ __die(msg, regs, __FILE__ ":"__FUNCTION__, __LINE__) diff --git a/include/asm-mips/termios.h b/include/asm-mips/termios.h index f31509f58a36..d60a4fb4945b 100644 --- a/include/asm-mips/termios.h +++ b/include/asm-mips/termios.h @@ -1,10 +1,9 @@ -/* $Id: termios.h,v 1.8 2000/01/27 23:45:30 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1995, 1996 by Ralf Baechle + * Copyright (C) 1995, 1996, 2001 by Ralf Baechle */ #ifndef _ASM_TERMIOS_H #define _ASM_TERMIOS_H diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h new file mode 100644 index 000000000000..436bb7c360a1 --- /dev/null +++ b/include/asm-mips/time.h @@ -0,0 +1,66 @@ +/*********************************************************************** + * Copyright 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * include/asm-mips/time.h + * header file for the new style time.c file and time services. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + *********************************************************************** + */ + +#ifndef _ASM_TIME_H +#define _ASM_TIME_H + +#include <linux/ptrace.h> /* for struct pt_regs */ +#include <linux/linkage.h> /* for asmlinkage */ + +/* + * RTC ops. By default, they point a no-RTC functions. + * rtc_get_time - mktime(year, mon, day, hour, min, sec) in seconds. + * rtc_set_time - reverse the above translation + */ +extern unsigned long (*rtc_get_time)(void); +extern int (*rtc_set_time)(unsigned long); + +/* + * do_gettimeoffset(). By default, this func pointer points to + * do_null_gettimeoffset(), which leads to the same resolution as HZ. + * Higher resolution versions are vailable. + */ +extern unsigned long (*do_gettimeoffset)(void); + +extern unsigned long null_gettimeoffset(void); +extern unsigned long fixed_rate_gettimeoffset(void); +extern unsigned long calibrate_div32_gettimeoffset(void); +extern unsigned long calibrate_div64_gettimeoffset(void); + +/* + * high-level timer interrupt routines. + */ +extern void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +/* + * the corresponding low-level timer interrupt routine. + */ +asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs); + +/* + * board specific routines required by time_init(). + * board_time_init is defaulted to NULL and can remains so. + * board_timer_setup must be setup properly in machine setup routine. + */ +struct irqaction; +extern void (*board_time_init)(void); +extern void (*board_timer_setup)(struct irqaction *irq); + +/* + * mips_counter_frequency - must be set if you intend to use + * counter as timer interrupt source or use fixed_rate_gettimeoffset. + */ +extern unsigned int mips_counter_frequency; + +#endif /* _ASM_TIME_H */ diff --git a/include/asm-mips/tlb.h b/include/asm-mips/tlb.h new file mode 100644 index 000000000000..69c0faa93194 --- /dev/null +++ b/include/asm-mips/tlb.h @@ -0,0 +1 @@ +#include <asm-generic/tlb.h> diff --git a/include/asm-mips/tx3912.h b/include/asm-mips/tx3912.h new file mode 100644 index 000000000000..64f81bea9034 --- /dev/null +++ b/include/asm-mips/tx3912.h @@ -0,0 +1,576 @@ +/* + * linux/include/asm-mips/tx3912.h + * + * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Register includes for TMPR3912/05 and PR31700 processors + */ +#ifndef __TX3912_H__ +#define __TX3912_H__ + +#include <asm/addrspace.h> + +#define inb(addr) (*(volatile unsigned char *)(addr)) +#define inw(addr) (*(volatile unsigned short *)(addr)) +#define inl(addr) (*(volatile unsigned int *)(addr)) +#define outb(b,addr) (*(volatile unsigned char *)(addr)) = (b) +#define outw(b,addr) (*(volatile unsigned short *)(addr)) = (b) +#define outl(b,addr) (*(volatile unsigned int *)(addr)) = (b) + + +/****************************************************************************** +* +* 01 General macro definitions +* +******************************************************************************/ + +#define REGISTER_BASE 0xb0c00000 + +#ifndef _LANGUAGE_ASSEMBLY + + #define REG_AT(x) (*((volatile unsigned long *)(REGISTER_BASE + x))) + +#else + + #define REG_AT(x) (REGISTER_BASE + x) + +#endif + +#define BIT(x) (1 << x) + +/****************************************************************************** +* +* 02 Bus Interface Unit +* +******************************************************************************/ + +#define MemConfig0 REG_AT(0x000) +#define MemConfig1 REG_AT(0x004) +#define MemConfig2 REG_AT(0x008) +#define MemConfig3 REG_AT(0x00c) +#define MemConfig4 REG_AT(0x010) +#define MemConfig5 REG_AT(0x014) +#define MemConfig6 REG_AT(0x018) +#define MemConfig7 REG_AT(0x01c) +#define MemConfig8 REG_AT(0x020) + +/* Memory config register 1 */ +#define MEM1_ENCS1USER BIT(21) + +/* Memory config register 3 */ +#define MEM3_CARD1ACCVAL_MASK (BIT(24) | BIT(25) | BIT(26) | BIT(27)) +#define MEM3_CARD1IOEN BIT(4) + +/* Memory config register 4 */ +#define MEM4_ARBITRATIONEN BIT(29) +#define MEM4_MEMPOWERDOWN BIT(16) +#define MEM4_ENREFRESH1 BIT(15) +#define MEM4_ENREFRESH0 BIT(14) +#define MEM4_ENWATCH BIT(24) +#define MEM4_WATCHTIMEVAL_MASK (0xf) +#define MEM4_WATCHTIMEVAL_SHIFT (20) +#define MEM4_WATCHTIME_VALUE (0xf) + +/* + *********************************************************************** + * * + * 06 Clock Module * + * * + *********************************************************************** + */ +#define TX3912_CLK_CTRL_BASE (REGISTER_BASE + 0x1c0) + +#define TX3912_CLK_CTRL_CHICLKDIV_MASK 0xff000000 +#define TX3912_CLK_CTRL_CHICLKDIV_SHIFT 24 +#define TX3912_CLK_CTRL_ENCLKTEST 0x00800000 +#define TX3912_CLK_CTRL_CLKTESTSELSIB 0x00400000 +#define TX3912_CLK_CTRL_CHIMCLKSEL 0x00200000 +#define TX3912_CLK_CTRL_CHICLKDIR 0x00100000 +#define TX3912_CLK_CTRL_ENCHIMCLK 0x00080000 +#define TX3912_CLK_CTRL_ENVIDCLK 0x00040000 +#define TX3912_CLK_CTRL_ENMBUSCLK 0x00020000 +#define TX3912_CLK_CTRL_ENSPICLK 0x00010000 +#define TX3912_CLK_CTRL_ENTIMERCLK 0x00008000 +#define TX3912_CLK_CTRL_ENFASTTIMERCLK 0x00004000 +#define TX3912_CLK_CTRL_SIBMCLKDIR 0x00002000 +#define TX3912_CLK_CTRL_RESERVED 0x00001000 +#define TX3912_CLK_CTRL_ENSIBMCLK 0x00000800 +#define TX3912_CLK_CTRL_SIBMCLKDIV_MASK 0x00000700 +#define TX3912_CLK_CTRL_SIBMCLKDIV_SHIFT 8 +#define TX3912_CLK_CTRL_CSERSEL 0x00000080 +#define TX3912_CLK_CTRL_CSERDIV_MASK 0x00000070 +#define TX3912_CLK_CTRL_CSERDIV_SHIFT 4 +#define TX3912_CLK_CTRL_ENCSERCLK 0x00000008 +#define TX3912_CLK_CTRL_ENIRCLK 0x00000004 +#define TX3912_CLK_CTRL_ENUARTACLK 0x00000002 +#define TX3912_CLK_CTRL_ENUARTBCLK 0x00000001 + + + + +/****************************************************************************** +* +* 07 CHI module +* +******************************************************************************/ + +#define CHIControl REG_AT(0x1D8) +#define CHIPointerEnable REG_AT(0x1DC) +#define CHIReceivePtrA REG_AT(0x1E0) +#define CHIReceivePtrB REG_AT(0x1E4) +#define CHITransmitPtrA REG_AT(0x1E8) +#define CHITransmitPtrB REG_AT(0x1EC) +#define CHISize REG_AT(0x1F0) +#define CHIReceiveStart REG_AT(0x1F4) +#define CHITransmitStart REG_AT(0x1F8) +#define CHIHoldingReg REG_AT(0x1FC) + +/* CHI Control Register */ +/* <incomplete!> */ +#define CHI_RXEN BIT(2) +#define CHI_TXEN BIT(1) +#define CHI_ENCHI BIT(0) + +/****************************************************************************** +* +* 08 Interrupt module +* +******************************************************************************/ + +/* Register locations */ + +#define IntStatus1 REG_AT(0x100) +#define IntStatus2 REG_AT(0x104) +#define IntStatus3 REG_AT(0x108) +#define IntStatus4 REG_AT(0x10c) +#define IntStatus5 REG_AT(0x110) +#define IntStatus6 REG_AT(0x114) + +#define IntClear1 REG_AT(0x100) +#define IntClear2 REG_AT(0x104) +#define IntClear3 REG_AT(0x108) +#define IntClear4 REG_AT(0x10c) +#define IntClear5 REG_AT(0x110) +#define IntClear6 REG_AT(0x114) + +#define IntEnable1 REG_AT(0x118) +#define IntEnable2 REG_AT(0x11c) +#define IntEnable3 REG_AT(0x120) +#define IntEnable4 REG_AT(0x124) +#define IntEnable5 REG_AT(0x128) +#define IntEnable6 REG_AT(0x12c) + +/* Interrupt Status Register 1 at offset 100 */ +#define INT1_LCDINT BIT(31) +#define INT1_DFINT BIT(30) +#define INT1_CHIDMAHALF BIT(29) +#define INT1_CHIDMAFULL BIT(28) +#define INT1_CHIDMACNTINT BIT(27) +#define INT1_CHIRXAINT BIT(26) +#define INT1_CHIRXBINT BIT(25) +#define INT1_CHIACTINT BIT(24) +#define INT1_CHIERRINT BIT(23) +#define INT1_SND0_5INT BIT(22) +#define INT1_SND1_0INT BIT(21) +#define INT1_TEL0_5INT BIT(20) +#define INT1_TEL1_0INT BIT(19) +#define INT1_SNDDMACNTINT BIT(18) +#define INT1_TELDMACNTINT BIT(17) +#define INT1_LSNDCLIPINT BIT(16) +#define INT1_RSNDCLIPINT BIT(15) +#define INT1_VALSNDPOSINT BIT(14) +#define INT1_VALSNDNEGINT BIT(13) +#define INT1_VALTELPOSINT BIT(12) +#define INT1_VALTELNEGINT BIT(11) +#define INT1_SNDININT BIT(10) +#define INT1_TELININT BIT(9) +#define INT1_SIBSF0INT BIT(8) +#define INT1_SIBSF1INT BIT(7) +#define INT1_SIBIRQPOSINT BIT(6) +#define INT1_SIBIRQNEGINT BIT(5) + +/* Interrupt Status Register 2 at offset 104 */ +#define INT2_UARTARXINT BIT(31) +#define INT2_UARTARXOVERRUN BIT(30) +#define INT2_UARTAFRAMEINT BIT(29) +#define INT2_UARTABREAKINT BIT(28) +#define INT2_UARTATXINT BIT(26) +#define INT2_UARTATXOVERRUN BIT(25) +#define INT2_UARTAEMPTY BIT(24) + +#define INT2_UARTBRXINT BIT(21) +#define INT2_UARTBRXOVERRUN BIT(20) +#define INT2_UARTBFRAMEINT BIT(29) +#define INT2_UARTBBREAKINT BIT(18) +#define INT2_UARTBTXINT BIT(16) +#define INT2_UARTBTXOVERRUN BIT(15) +#define INT2_UARTBEMPTY BIT(14) + +#define INT2_UARTA_RX (BIT(31) | BIT(30) | BIT(29) | BIT(28) | BIT(27)) +#define INT2_UARTA_TX (BIT(26) | BIT(25) | BIT(24)) +#define INT2_UARTA_DMA (BIT(23) | BIT(22)) + +#define INT2_UARTB_RX (BIT(21) | BIT(20) | BIT(19) | BIT(18) | BIT(17)) +#define INT2_UARTB_TX (BIT(16) | BIT(15) | BIT(14)) +#define INT2_UARTB_DMA (BIT(13) | BIT(12)) + +/* Interrupt Status Register 5 */ +#define INT5_RTCINT BIT(31) +#define INT5_ALARMINT BIT(30) +#define INT5_PERIODICINT BIT(29) +#define INT5_POSPWRINT BIT(27) +#define INT5_NEGPWRINT BIT(26) +#define INT5_POSPWROKINT BIT(25) +#define INT5_NEGPWROKINT BIT(24) +#define INT5_POSONBUTINT BIT(23) +#define INT5_NEGONBUTINT BIT(22) +#define INT5_SPIAVAILINT BIT(21) /* 0x0020 0000 */ +#define INT5_SPIERRINT BIT(20) /* 0x0010 0000 */ +#define INT5_SPIRCVINT BIT(19) /* 0x0008 0000 */ +#define INT5_SPIEMPTYINT BIT(18) /* 0x0004 0000 */ +#define INT5_IOPOSINT6 BIT(13) +#define INT5_IOPOSINT5 BIT(12) +#define INT5_IOPOSINT4 BIT(11) +#define INT5_IOPOSINT3 BIT(10) +#define INT5_IOPOSINT2 BIT(9) +#define INT5_IOPOSINT1 BIT(8) +#define INT5_IOPOSINT0 BIT(7) +#define INT5_IONEGINT6 BIT(6) +#define INT5_IONEGINT5 BIT(5) +#define INT5_IONEGINT4 BIT(4) +#define INT5_IONEGINT3 BIT(3) +#define INT5_IONEGINT2 BIT(2) +#define INT5_IONEGINT1 BIT(1) +#define INT5_IONEGINT0 BIT(0) + +#define INT5_IONEGINT_SHIFT 0 +#define INT5_IONEGINT_MASK (0x7F<<INT5_IONEGINT_SHIFT) +#define INT5_IOPOSINT_SHIFT 7 +#define INT5_IOPOSINT_MASK (0x7F<<INT5_IOPOSINT_SHIFT) + +/* Interrupt Status Register 6 */ +#define INT6_IRQHIGH BIT(31) +#define INT6_IRQLOW BIT(30) +#define INT6_INTVECT (BIT(5) | BIT(4) | BIT(3) | BIT(2)) + + +/* Interrupt Enable Register 6 */ +#define INT6_GLOBALEN BIT(18) +#define INT6_PWROKINT BIT(15) +#define INT6_ALARMINT BIT(14) +#define INT6_PERIODICINT BIT(13) +#define INT6_MBUSINT BIT(12) +#define INT6_UARTARXINT BIT(11) +#define INT6_UARTBRXINT BIT(10) +#define INT6_MFIOPOSINT1619 BIT(9) +#define INT6_IOPOSINT56 BIT(8) +#define INT6_MFIONEGINT1619 BIT(7) +#define INT6_IONEGINT56 BIT(6) +#define INT6_MBUSDMAFULLINT BIT(5) +#define INT6_SNDDMACNTINT BIT(4) +#define INT6_TELDMACNTINT BIT(3) +#define INT6_CHIDMACNTINT BIT(2) +#define INT6_IOPOSNEGINT0 BIT(1) + +/****************************************************************************** +* +* 09 GPIO and MFIO modules +* +******************************************************************************/ + +#define IOControl REG_AT(0x180) +#define MFIOOutput REG_AT(0x184) +#define MFIODirection REG_AT(0x188) +#define MFIOInput REG_AT(0x18c) +#define MFIOSelect REG_AT(0x190) +#define IOPowerDown REG_AT(0x194) +#define MFIOPowerDown REG_AT(0x198) + +#define IODIN_MASK 0x0000007f +#define IODIN_SHIFT 0 +#define IODOUT_MASK 0x00007f00 +#define IODOUT_SHIFT 8 +#define IODIREC_MASK 0x007f0000 +#define IODIREC_SHIFT 16 +#define IODEBSEL_MASK 0x7f000000 +#define IODEBSEL_SHIFT 24 + +/****************************************************************************** +* +* 10 IR module +* +******************************************************************************/ + +#define IRControl1 REG_AT(0x0a0) +#define IRControl2 REG_AT(0x0a4) + +/* IR Control 1 Register */ +#define IR_CARDRET BIT(24) +#define IR_BAUDVAL_MASK 0x00ff0000 +#define IR_BAUDVAL_SHIFT 16 +#define IR_TESTIR BIT(4) +#define IR_DTINVERT BIT(3) +#define IR_RXPWR BIT(2) +#define IR_ENSTATE BIT(1) +#define IR_ENCONSM BIT(0) + +/* IR Control 2 Register */ +#define IR_PER_MASK 0xff000000 +#define IR_PER_SHIFT 24 +#define IR_ONTIME_MASK 0x00ff0000 +#define IR_ONTIME_SHIFT 16 +#define IR_DELAYVAL_MASK 0x0000ff00 +#define IR_DELAYVAL_SHIFT 8 +#define IR_WAITVAL_MASK 0x000000ff +#define IR_WAITVAL_SHIFT 0 + +/****************************************************************************** +* +* 11 Magicbus Module +* +******************************************************************************/ + +#define MbusCntrl1 REG_AT(0x0e0) +#define MbusCntrl2 REG_AT(0x0e4) +#define MbusDMACntrl1 REG_AT(0x0e8) +#define MbusDMACntrl2 REG_AT(0x0ec) +#define MbusDMACount REG_AT(0x0f0) +#define MbusTxReg REG_AT(0x0f4) +#define MbusRxReg REG_AT(0x0f8) + +#define MBUS_CLKPOL BIT(4) +#define MBUS_SLAVE BIT(3) +#define MBUS_FSLAVE BIT(2) +#define MBUS_LONG BIT(1) +#define MBUS_ENMBUS BIT(0) + +/****************************************************************************** +* +* 12 Power module +* +******************************************************************************/ + +#define PowerControl REG_AT(0x1C4) + +#define PWR_ONBUTN BIT(31) +#define PWR_PWRINT BIT(30) +#define PWR_PWROK BIT(29) +#define PWR_VIDRF_MASK (BIT(28) | BIT(27)) +#define PWR_VIDRF_SHIFT 27 +#define PWR_SLOWBUS BIT(26) +#define PWR_DIVMOD BIT(25) +#define PWR_STPTIMERVAL_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12)) +#define PWR_STPTIMERVAL_SHIFT 12 +#define PWR_ENSTPTIMER BIT(11) +#define PWR_ENFORCESHUTDWN BIT(10) +#define PWR_FORCESHUTDWN BIT(9) +#define PWR_FORCESHUTDWNOCC BIT(8) +#define PWR_SELC2MS BIT(7) +#define PWR_BPDBVCC3 BIT(5) +#define PWR_STOPCPU BIT(4) +#define PWR_DBNCONBUTN BIT(3) +#define PWR_COLDSTART BIT(2) +#define PWR_PWRCS BIT(1) +#define PWR_VCCON BIT(0) + +/****************************************************************************** +* +* 13 SIB (Serial Interconnect Bus) Module +* +******************************************************************************/ + +/* Register locations */ +#define SIBSize REG_AT(0x060) +#define SIBSoundRXStart REG_AT(0x064) +#define SIBSoundTXStart REG_AT(0x068) +#define SIBTelecomRXStart REG_AT(0x06C) +#define SIBTelecomTXStart REG_AT(0x070) +#define SIBControl REG_AT(0x074) +#define SIBSoundTXRXHolding REG_AT(0x078) +#define SIBTelecomTXRXHolding REG_AT(0x07C) +#define SIBSubFrame0Control REG_AT(0x080) +#define SIBSubFrame1Control REG_AT(0x084) +#define SIBSubFrame0Status REG_AT(0x088) +#define SIBSubFrame1Status REG_AT(0x08C) +#define SIBDMAControl REG_AT(0x090) + +/* SIB Size Register */ +#define SIB_SNDSIZE_MASK 0x3ffc0000 +#define SIB_SNDSIZE_SHIFT 18 +#define SIB_TELSIZE_MASK 0x00003ffc +#define SIB_TELSIZE_SHIFT 2 + +/* SIB Control Register */ +#define SIB_SIBIRQ BIT(31) +#define SIB_ENCNTTEST BIT(30) +#define SIB_ENDMATEST BIT(29) +#define SIB_SNDMONO BIT(28) +#define SIB_RMONOSNDIN BIT(27) +#define SIB_SIBSCLKDIV_MASK (BIT(26) | BIT(25) | BIT(24)) +#define SIB_SIBSCLKDIV_SHIFT 24 +#define SIB_TEL16 BIT(23) +#define SIB_TELFSDIV_MASK 0x007f0000 +#define SIB_TELFSDIV_SHIFT 16 +#define SIB_SND16 BIT(15) +#define SIB_SNDFSDIV_MASK 0x00007f00 +#define SIB_SNDFSDIV_SHIFT 8 +#define SIB_SELTELSF1 BIT(7) +#define SIB_SELSNDSF1 BIT(6) +#define SIB_ENTEL BIT(5) +#define SIB_ENSND BIT(4) +#define SIB_SIBLOOP BIT(3) +#define SIB_ENSF1 BIT(2) +#define SIB_ENSF0 BIT(1) +#define SIB_ENSIB BIT(0) + +/* SIB Frame Format (SIBSubFrame0Status and SIBSubFrame1Status) */ +#define SIB_REGISTER_EXT BIT(31) /* Must be zero */ +#define SIB_ADDRESS_MASK 0x78000000 +#define SIB_ADDRESS_SHIFT 27 +#define SIB_WRITE BIT(26) +#define SIB_AUD_VALID BIT(17) +#define SIB_TEL_VALID BIT(16) +#define SIB_DATA_MASK 0x00ff +#define SIB_DATA_SHIFT 0 + +/* SIB DMA Control Register */ +#define SIB_SNDBUFF1TIME BIT(31) +#define SIB_SNDDMALOOP BIT(30) +#define SIB_SNDDMAPTR_MASK 0x3ffc0000 +#define SIB_SNDDMAPTR_SHIFT 18 +#define SIB_ENDMARXSND BIT(17) +#define SIB_ENDMATXSND BIT(16) +#define SIB_TELBUFF1TIME BIT(15) +#define SIB_TELDMALOOP BIT(14) +#define SIB_TELDMAPTR_MASK 0x00003ffc +#define SIB_TELDMAPTR_SHIFT 2 +#define SIB_ENDMARXTEL BIT(1) +#define SIB_ENDMATXTEL BIT(0) + +/****************************************************************************** +* +* 14 SPI module +* +******************************************************************************/ + +#define SPIControl REG_AT(0x160) +#define SPITransmit REG_AT(0x164) +#define SPIReceive REG_AT(0x164) + +#define SPI_SPION BIT(17) +#define SPI_EMPTY BIT(16) +#define SPI_DELAYVAL_MASK (BIT(12) | BIT(13) | BIT(14) | BIT(15)) +#define SPI_DELAYVAL_SHIFT 12 +#define SPI_BAUDRATE_MASK (BIT(8) | BIT(9) | BIT(10) | BIT(11)) +#define SPI_BAUDRATE_SHIFT 8 +#define SPI_PHAPOL BIT(5) +#define SPI_CLKPOL BIT(4) +#define SPI_WORD BIT(2) +#define SPI_LSB BIT(1) +#define SPI_ENSPI BIT(0) + +/****************************************************************************** +* +* 15 Timer module +* +******************************************************************************/ + +#define RTChigh REG_AT(0x140) +#define RTClow REG_AT(0x144) +#define RTCalarmHigh REG_AT(0x148) +#define RTCalarmLow REG_AT(0x14c) +#define RTCtimerControl REG_AT(0x150) +#define RTCperiodTimer REG_AT(0x154) + +/* RTC Timer Control */ +#define TIM_FREEZEPRE BIT(7) +#define TIM_FREEZERTC BIT(6) +#define TIM_FREEZETIMER BIT(5) +#define TIM_ENPERTIMER BIT(4) +#define TIM_RTCCLEAR BIT(3) + +#define RTC_HIGHMASK (0xFF) + +/* RTC Periodic Timer */ +#define TIM_PERCNT 0xFFFF0000 +#define TIM_PERVAL 0x0000FFFF + +/* For a system clock frequency of 36.864MHz, the timer counts at one tick + every 868nS (ie CLK/32). Therefore 11520 counts gives a 10mS interval + */ +#define PER_TIMER_COUNT (1152000/HZ) + +/* + *********************************************************************** + * * + * 15 UART Module * + * * + *********************************************************************** + */ +#define TX3912_UARTA_BASE (REGISTER_BASE + 0x0b0) +#define TX3912_UARTB_BASE (REGISTER_BASE + 0x0c8) + +/* + * TX3912 UART register offsets + */ +#define TX3912_UART_CTRL1 0x00 +#define TX3912_UART_CTRL2 0x04 +#define TX3912_UART_DMA_CTRL1 0x08 +#define TX3912_UART_DMA_CTRL2 0x0c +#define TX3912_UART_DMA_CNT 0x10 +#define TX3912_UART_DATA 0x14 + +#define UartA_Ctrl1 REG_AT(0x0b0) +#define UartA_Data REG_AT(0x0c4) + +/* + * Defines for UART Control Register 1 + */ +#define TX3912_UART_CTRL1_UARTON 0x80000000 +#define UART_TX_EMPTY BIT(30) +#define UART_PRX_HOLD_FULL BIT(29) +#define UART_RX_HOLD_FULL BIT(28) +#define UART_EN_DMA_RX BIT(15) +#define UART_EN_DMA_TX BIT(14) +#define UART_BREAK_HALT BIT(12) +#define UART_DMA_LOOP BIT(10) +#define UART_PULSE_THREE BIT(9) +#define UART_PULSE_SIX BIT(8) +#define UART_DT_INVERT BIT(7) +#define UART_DIS_TXD BIT(6) +#define UART_LOOPBACK BIT(4) +#define TX3912_UART_CTRL1_ENUART 0x00000001 + +#define SER_SEVEN_BIT BIT(3) +#define SER_EIGHT_BIT 0 +#define SER_EVEN_PARITY (BIT(2) | BIT(1)) +#define SER_ODD_PARITY BIT(1) +#define SER_NO_PARITY 0 +#define SER_TWO_STOP BIT(5) +#define SER_ONE_STOP 0 + +/* + * Defines for UART Control Register 2 + * + * 3.6864MHz + * divisors = ----------- - 1 + * (baud * 16) + */ +#define TX3912_UART_CTRL2_B230400 0x000 /* 0 */ +#define TX3912_UART_CTRL2_B115200 0x001 /* 1 */ +#define TX3912_UART_CTRL2_B76800 0x002 /* 2 */ +#define TX3912_UART_CTRL2_B57600 0x003 /* 3 */ +#define TX3912_UART_CTRL2_B38400 0x005 /* 5 */ +#define TX3912_UART_CTRL2_B19200 0x00b /* 11 */ +#define TX3912_UART_CTRL2_B9600 0x016 /* 22 */ +#define TX3912_UART_CTRL2_B4800 0x02f /* 47 */ +#define TX3912_UART_CTRL2_B2400 0x05f /* 95 */ +#define TX3912_UART_CTRL2_B1200 0x0bf /* 191 */ +#define TX3912_UART_CTRL2_B600 0x17f /* 383 */ +#define TX3912_UART_CTRL2_B300 0x2ff /* 767 */ + +#endif /* __TX3912_H__ */ diff --git a/include/asm-mips/unaligned.h b/include/asm-mips/unaligned.h index 622e1e977400..2b0174925f22 100644 --- a/include/asm-mips/unaligned.h +++ b/include/asm-mips/unaligned.h @@ -1,10 +1,10 @@ -/* $Id$ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996, 1999 by Ralf Baechle + * Copyright (C) 1996, 1999, 2000 by Ralf Baechle + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ #ifndef _ASM_UNALIGNED_H #define _ASM_UNALIGNED_H @@ -13,133 +13,147 @@ extern void __get_unaligned_bad_length(void); extern void __put_unaligned_bad_length(void); /* - * Load quad unaligned. + * Load double unaligned. + * + * This could have been implemented in plain C like IA64 but egcs 1.0.3a + * inflates this to 23 instructions ... */ -extern __inline__ unsigned long ldq_u(const unsigned long long * __addr) +extern inline unsigned long long __ldq_u(const unsigned long long * __addr) { unsigned long long __res; - __asm__("uld\t%0,(%1)" - :"=&r" (__res) - :"r" (__addr)); + __asm__("ulw\t%0, %1\n\t" + "ulw\t%D0, 4+%1" + : "=&r" (__res) + : "m" (*__addr)); return __res; } /* - * Load long unaligned. + * Load word unaligned. */ -extern __inline__ unsigned long ldl_u(const unsigned int * __addr) +extern inline unsigned long __ldl_u(const unsigned int * __addr) { unsigned long __res; - __asm__("ulw\t%0,(%1)" - :"=&r" (__res) - :"r" (__addr)); + __asm__("ulw\t%0,%1" + : "=&r" (__res) + : "m" (*__addr)); return __res; } /* - * Load word unaligned. + * Load halfword unaligned. */ -extern __inline__ unsigned long ldw_u(const unsigned short * __addr) +extern inline unsigned long __ldw_u(const unsigned short * __addr) { unsigned long __res; - __asm__("ulh\t%0,(%1)" - :"=&r" (__res) - :"r" (__addr)); + __asm__("ulh\t%0,%1" + : "=&r" (__res) + : "m" (*__addr)); return __res; } /* - * Store quad ununaligned. + * Store doubleword ununaligned. */ -extern __inline__ void stq_u(unsigned long __val, unsigned long long * __addr) +extern inline void __stq_u(unsigned long __val, unsigned long long * __addr) { - __asm__ __volatile__( - "usd\t%0,(%1)" - : /* No results */ - :"r" (__val), - "r" (__addr)); + __asm__("usw\t%1, %0\n\t" + "usw\t%D1, 4+%0" + : "=m" (*__addr) + : "r" (__val)); } /* * Store long ununaligned. */ -extern __inline__ void stl_u(unsigned long __val, unsigned int * __addr) +extern inline void __stl_u(unsigned long __val, unsigned int * __addr) { - __asm__ __volatile__( - "usw\t%0,(%1)" - : /* No results */ - :"r" (__val), - "r" (__addr)); + __asm__("usw\t%1, %0" + : "=m" (*__addr) + : "r" (__val)); } /* * Store word ununaligned. */ -extern __inline__ void stw_u(unsigned long __val, unsigned short * __addr) +extern inline void __stw_u(unsigned long __val, unsigned short * __addr) { - __asm__ __volatile__( - "ush\t%0,(%1)" - : /* No results */ - :"r" (__val), - "r" (__addr)); + __asm__("ush\t%1, %0" + : "=m" (*__addr) + : "r" (__val)); } -extern inline unsigned long __get_unaligned(const void *ptr, size_t size) -{ - unsigned long val; - switch (size) { - case 1: - val = *(const unsigned char *)ptr; - break; - case 2: - val = ldw_u((const unsigned short *)ptr); - break; - case 4: - val = ldl_u((const unsigned int *)ptr); - break; - case 8: - val = ldq_u((const unsigned long long *)ptr); - break; - default: - __get_unaligned_bad_length(); - break; - } - return val; -} - -extern inline void __put_unaligned(unsigned long val, void *ptr, size_t size) -{ - switch (size) { - case 1: - *(unsigned char *)ptr = (val); - break; - case 2: - stw_u(val, (unsigned short *)ptr); - break; - case 4: - stl_u(val, (unsigned int *)ptr); - break; - case 8: - stq_u(val, (unsigned long long *)ptr); - break; - default: - __put_unaligned_bad_length(); - break; - } -} +/* + * get_unaligned - get value from possibly mis-aligned location + * @ptr: pointer to value + * + * This macro should be used for accessing values larger in size than + * single bytes at locations that are expected to be improperly aligned, + * e.g. retrieving a u16 value from a location not u16-aligned. + * + * Note that unaligned accesses can be very expensive on some architectures. + */ +#define get_unaligned(ptr) \ +({ \ + __typeof__(*(ptr)) __val; \ + \ + switch (sizeof(*(ptr))) { \ + case 1: \ + __val = *(const unsigned char *)ptr; \ + break; \ + case 2: \ + __val = __ldw_u((const unsigned short *)ptr); \ + break; \ + case 4: \ + __val = __ldl_u((const unsigned int *)ptr); \ + break; \ + case 8: \ + __val = __ldq_u((const unsigned long long *)ptr); \ + break; \ + default: \ + __get_unaligned_bad_length(); \ + break; \ + } \ + \ + __val; \ +}) -/* - * The main single-value unaligned transfer routines. +/* + * put_unaligned - put value to a possibly mis-aligned location + * @val: value to place + * @ptr: pointer to location + * + * This macro should be used for placing values larger in size than + * single bytes at locations that are expected to be improperly aligned, + * e.g. writing a u16 value to a location not u16-aligned. + * + * Note that unaligned accesses can be very expensive on some architectures. */ -#define get_unaligned(ptr) \ - ((__typeof__(*(ptr)))__get_unaligned((ptr), sizeof(*(ptr)))) -#define put_unaligned(x,ptr) \ - __put_unaligned((unsigned long)(x), (ptr), sizeof(*(ptr))) +#define put_unaligned(val,ptr) \ +do { \ + switch (sizeof(*(ptr))) { \ + case 1: \ + *(unsigned char *)(ptr) = (val); \ + break; \ + case 2: \ + __stw_u(val, (unsigned short *)(ptr)); \ + break; \ + case 4: \ + __stl_u(val, (unsigned int *)(ptr)); \ + break; \ + case 8: \ + __stq_u(val, (unsigned long long *)(ptr)); \ + break; \ + default: \ + __put_unaligned_bad_length(); \ + break; \ + } \ +} while(0) #endif /* _ASM_UNALIGNED_H */ diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h index 46986ccfa2d9..97d031618666 100644 --- a/include/asm-mips/unistd.h +++ b/include/asm-mips/unistd.h @@ -1,990 +1,16 @@ -/* $Id: unistd.h,v 1.20 2000/02/18 00:24:48 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle + * Copyright (C) 1995, 96, 97, 98, 99, 2000 by Ralf Baechle * * Changed system calls macros _syscall5 - _syscall7 to push args 5 to 7 onto * the stack. Robin Farine for ACN S.A, Copyright (C) 1996 by ACN S.A */ -#ifndef __ASM_MIPS_UNISTD_H -#define __ASM_MIPS_UNISTD_H - -/* - * The syscalls 0 - 3999 are reserved for a down to the root syscall - * compatibility with RISC/os and IRIX. We'll see how to deal with the - * various "real" BSD variants like Ultrix, NetBSD ... - */ - -/* - * SVR4 syscalls are in the range from 1 to 999 - */ -#define __NR_SVR4 0 -#define __NR_SVR4_syscall (__NR_SVR4 + 0) -#define __NR_SVR4_exit (__NR_SVR4 + 1) -#define __NR_SVR4_fork (__NR_SVR4 + 2) -#define __NR_SVR4_read (__NR_SVR4 + 3) -#define __NR_SVR4_write (__NR_SVR4 + 4) -#define __NR_SVR4_open (__NR_SVR4 + 5) -#define __NR_SVR4_close (__NR_SVR4 + 6) -#define __NR_SVR4_wait (__NR_SVR4 + 7) -#define __NR_SVR4_creat (__NR_SVR4 + 8) -#define __NR_SVR4_link (__NR_SVR4 + 9) -#define __NR_SVR4_unlink (__NR_SVR4 + 10) -#define __NR_SVR4_exec (__NR_SVR4 + 11) -#define __NR_SVR4_chdir (__NR_SVR4 + 12) -#define __NR_SVR4_gtime (__NR_SVR4 + 13) -#define __NR_SVR4_mknod (__NR_SVR4 + 14) -#define __NR_SVR4_chmod (__NR_SVR4 + 15) -#define __NR_SVR4_chown (__NR_SVR4 + 16) -#define __NR_SVR4_sbreak (__NR_SVR4 + 17) -#define __NR_SVR4_stat (__NR_SVR4 + 18) -#define __NR_SVR4_lseek (__NR_SVR4 + 19) -#define __NR_SVR4_getpid (__NR_SVR4 + 20) -#define __NR_SVR4_mount (__NR_SVR4 + 21) -#define __NR_SVR4_umount (__NR_SVR4 + 22) -#define __NR_SVR4_setuid (__NR_SVR4 + 23) -#define __NR_SVR4_getuid (__NR_SVR4 + 24) -#define __NR_SVR4_stime (__NR_SVR4 + 25) -#define __NR_SVR4_ptrace (__NR_SVR4 + 26) -#define __NR_SVR4_alarm (__NR_SVR4 + 27) -#define __NR_SVR4_fstat (__NR_SVR4 + 28) -#define __NR_SVR4_pause (__NR_SVR4 + 29) -#define __NR_SVR4_utime (__NR_SVR4 + 30) -#define __NR_SVR4_stty (__NR_SVR4 + 31) -#define __NR_SVR4_gtty (__NR_SVR4 + 32) -#define __NR_SVR4_access (__NR_SVR4 + 33) -#define __NR_SVR4_nice (__NR_SVR4 + 34) -#define __NR_SVR4_statfs (__NR_SVR4 + 35) -#define __NR_SVR4_sync (__NR_SVR4 + 36) -#define __NR_SVR4_kill (__NR_SVR4 + 37) -#define __NR_SVR4_fstatfs (__NR_SVR4 + 38) -#define __NR_SVR4_setpgrp (__NR_SVR4 + 39) -#define __NR_SVR4_cxenix (__NR_SVR4 + 40) -#define __NR_SVR4_dup (__NR_SVR4 + 41) -#define __NR_SVR4_pipe (__NR_SVR4 + 42) -#define __NR_SVR4_times (__NR_SVR4 + 43) -#define __NR_SVR4_profil (__NR_SVR4 + 44) -#define __NR_SVR4_plock (__NR_SVR4 + 45) -#define __NR_SVR4_setgid (__NR_SVR4 + 46) -#define __NR_SVR4_getgid (__NR_SVR4 + 47) -#define __NR_SVR4_sig (__NR_SVR4 + 48) -#define __NR_SVR4_msgsys (__NR_SVR4 + 49) -#define __NR_SVR4_sysmips (__NR_SVR4 + 50) -#define __NR_SVR4_sysacct (__NR_SVR4 + 51) -#define __NR_SVR4_shmsys (__NR_SVR4 + 52) -#define __NR_SVR4_semsys (__NR_SVR4 + 53) -#define __NR_SVR4_ioctl (__NR_SVR4 + 54) -#define __NR_SVR4_uadmin (__NR_SVR4 + 55) -#define __NR_SVR4_exch (__NR_SVR4 + 56) -#define __NR_SVR4_utssys (__NR_SVR4 + 57) -#define __NR_SVR4_fsync (__NR_SVR4 + 58) -#define __NR_SVR4_exece (__NR_SVR4 + 59) -#define __NR_SVR4_umask (__NR_SVR4 + 60) -#define __NR_SVR4_chroot (__NR_SVR4 + 61) -#define __NR_SVR4_fcntl (__NR_SVR4 + 62) -#define __NR_SVR4_ulimit (__NR_SVR4 + 63) -#define __NR_SVR4_reserved1 (__NR_SVR4 + 64) -#define __NR_SVR4_reserved2 (__NR_SVR4 + 65) -#define __NR_SVR4_reserved3 (__NR_SVR4 + 66) -#define __NR_SVR4_reserved4 (__NR_SVR4 + 67) -#define __NR_SVR4_reserved5 (__NR_SVR4 + 68) -#define __NR_SVR4_reserved6 (__NR_SVR4 + 69) -#define __NR_SVR4_advfs (__NR_SVR4 + 70) -#define __NR_SVR4_unadvfs (__NR_SVR4 + 71) -#define __NR_SVR4_unused1 (__NR_SVR4 + 72) -#define __NR_SVR4_unused2 (__NR_SVR4 + 73) -#define __NR_SVR4_rfstart (__NR_SVR4 + 74) -#define __NR_SVR4_unused3 (__NR_SVR4 + 75) -#define __NR_SVR4_rdebug (__NR_SVR4 + 76) -#define __NR_SVR4_rfstop (__NR_SVR4 + 77) -#define __NR_SVR4_rfsys (__NR_SVR4 + 78) -#define __NR_SVR4_rmdir (__NR_SVR4 + 79) -#define __NR_SVR4_mkdir (__NR_SVR4 + 80) -#define __NR_SVR4_getdents (__NR_SVR4 + 81) -#define __NR_SVR4_libattach (__NR_SVR4 + 82) -#define __NR_SVR4_libdetach (__NR_SVR4 + 83) -#define __NR_SVR4_sysfs (__NR_SVR4 + 84) -#define __NR_SVR4_getmsg (__NR_SVR4 + 85) -#define __NR_SVR4_putmsg (__NR_SVR4 + 86) -#define __NR_SVR4_poll (__NR_SVR4 + 87) -#define __NR_SVR4_lstat (__NR_SVR4 + 88) -#define __NR_SVR4_symlink (__NR_SVR4 + 89) -#define __NR_SVR4_readlink (__NR_SVR4 + 90) -#define __NR_SVR4_setgroups (__NR_SVR4 + 91) -#define __NR_SVR4_getgroups (__NR_SVR4 + 92) -#define __NR_SVR4_fchmod (__NR_SVR4 + 93) -#define __NR_SVR4_fchown (__NR_SVR4 + 94) -#define __NR_SVR4_sigprocmask (__NR_SVR4 + 95) -#define __NR_SVR4_sigsuspend (__NR_SVR4 + 96) -#define __NR_SVR4_sigaltstack (__NR_SVR4 + 97) -#define __NR_SVR4_sigaction (__NR_SVR4 + 98) -#define __NR_SVR4_sigpending (__NR_SVR4 + 99) -#define __NR_SVR4_setcontext (__NR_SVR4 + 100) -#define __NR_SVR4_evsys (__NR_SVR4 + 101) -#define __NR_SVR4_evtrapret (__NR_SVR4 + 102) -#define __NR_SVR4_statvfs (__NR_SVR4 + 103) -#define __NR_SVR4_fstatvfs (__NR_SVR4 + 104) -#define __NR_SVR4_reserved7 (__NR_SVR4 + 105) -#define __NR_SVR4_nfssys (__NR_SVR4 + 106) -#define __NR_SVR4_waitid (__NR_SVR4 + 107) -#define __NR_SVR4_sigsendset (__NR_SVR4 + 108) -#define __NR_SVR4_hrtsys (__NR_SVR4 + 109) -#define __NR_SVR4_acancel (__NR_SVR4 + 110) -#define __NR_SVR4_async (__NR_SVR4 + 111) -#define __NR_SVR4_priocntlset (__NR_SVR4 + 112) -#define __NR_SVR4_pathconf (__NR_SVR4 + 113) -#define __NR_SVR4_mincore (__NR_SVR4 + 114) -#define __NR_SVR4_mmap (__NR_SVR4 + 115) -#define __NR_SVR4_mprotect (__NR_SVR4 + 116) -#define __NR_SVR4_munmap (__NR_SVR4 + 117) -#define __NR_SVR4_fpathconf (__NR_SVR4 + 118) -#define __NR_SVR4_vfork (__NR_SVR4 + 119) -#define __NR_SVR4_fchdir (__NR_SVR4 + 120) -#define __NR_SVR4_readv (__NR_SVR4 + 121) -#define __NR_SVR4_writev (__NR_SVR4 + 122) -#define __NR_SVR4_xstat (__NR_SVR4 + 123) -#define __NR_SVR4_lxstat (__NR_SVR4 + 124) -#define __NR_SVR4_fxstat (__NR_SVR4 + 125) -#define __NR_SVR4_xmknod (__NR_SVR4 + 126) -#define __NR_SVR4_clocal (__NR_SVR4 + 127) -#define __NR_SVR4_setrlimit (__NR_SVR4 + 128) -#define __NR_SVR4_getrlimit (__NR_SVR4 + 129) -#define __NR_SVR4_lchown (__NR_SVR4 + 130) -#define __NR_SVR4_memcntl (__NR_SVR4 + 131) -#define __NR_SVR4_getpmsg (__NR_SVR4 + 132) -#define __NR_SVR4_putpmsg (__NR_SVR4 + 133) -#define __NR_SVR4_rename (__NR_SVR4 + 134) -#define __NR_SVR4_nuname (__NR_SVR4 + 135) -#define __NR_SVR4_setegid (__NR_SVR4 + 136) -#define __NR_SVR4_sysconf (__NR_SVR4 + 137) -#define __NR_SVR4_adjtime (__NR_SVR4 + 138) -#define __NR_SVR4_sysinfo (__NR_SVR4 + 139) -#define __NR_SVR4_reserved8 (__NR_SVR4 + 140) -#define __NR_SVR4_seteuid (__NR_SVR4 + 141) -#define __NR_SVR4_PYRAMID_statis (__NR_SVR4 + 142) -#define __NR_SVR4_PYRAMID_tuning (__NR_SVR4 + 143) -#define __NR_SVR4_PYRAMID_forcerr (__NR_SVR4 + 144) -#define __NR_SVR4_PYRAMID_mpcntl (__NR_SVR4 + 145) -#define __NR_SVR4_reserved9 (__NR_SVR4 + 146) -#define __NR_SVR4_reserved10 (__NR_SVR4 + 147) -#define __NR_SVR4_reserved11 (__NR_SVR4 + 148) -#define __NR_SVR4_reserved12 (__NR_SVR4 + 149) -#define __NR_SVR4_reserved13 (__NR_SVR4 + 150) -#define __NR_SVR4_reserved14 (__NR_SVR4 + 151) -#define __NR_SVR4_reserved15 (__NR_SVR4 + 152) -#define __NR_SVR4_reserved16 (__NR_SVR4 + 153) -#define __NR_SVR4_reserved17 (__NR_SVR4 + 154) -#define __NR_SVR4_reserved18 (__NR_SVR4 + 155) -#define __NR_SVR4_reserved19 (__NR_SVR4 + 156) -#define __NR_SVR4_reserved20 (__NR_SVR4 + 157) -#define __NR_SVR4_reserved21 (__NR_SVR4 + 158) -#define __NR_SVR4_reserved22 (__NR_SVR4 + 159) -#define __NR_SVR4_reserved23 (__NR_SVR4 + 160) -#define __NR_SVR4_reserved24 (__NR_SVR4 + 161) -#define __NR_SVR4_reserved25 (__NR_SVR4 + 162) -#define __NR_SVR4_reserved26 (__NR_SVR4 + 163) -#define __NR_SVR4_reserved27 (__NR_SVR4 + 164) -#define __NR_SVR4_reserved28 (__NR_SVR4 + 165) -#define __NR_SVR4_reserved29 (__NR_SVR4 + 166) -#define __NR_SVR4_reserved30 (__NR_SVR4 + 167) -#define __NR_SVR4_reserved31 (__NR_SVR4 + 168) -#define __NR_SVR4_reserved32 (__NR_SVR4 + 169) -#define __NR_SVR4_reserved33 (__NR_SVR4 + 170) -#define __NR_SVR4_reserved34 (__NR_SVR4 + 171) -#define __NR_SVR4_reserved35 (__NR_SVR4 + 172) -#define __NR_SVR4_reserved36 (__NR_SVR4 + 173) -#define __NR_SVR4_reserved37 (__NR_SVR4 + 174) -#define __NR_SVR4_reserved38 (__NR_SVR4 + 175) -#define __NR_SVR4_reserved39 (__NR_SVR4 + 176) -#define __NR_SVR4_reserved40 (__NR_SVR4 + 177) -#define __NR_SVR4_reserved41 (__NR_SVR4 + 178) -#define __NR_SVR4_reserved42 (__NR_SVR4 + 179) -#define __NR_SVR4_reserved43 (__NR_SVR4 + 180) -#define __NR_SVR4_reserved44 (__NR_SVR4 + 181) -#define __NR_SVR4_reserved45 (__NR_SVR4 + 182) -#define __NR_SVR4_reserved46 (__NR_SVR4 + 183) -#define __NR_SVR4_reserved47 (__NR_SVR4 + 184) -#define __NR_SVR4_reserved48 (__NR_SVR4 + 185) -#define __NR_SVR4_reserved49 (__NR_SVR4 + 186) -#define __NR_SVR4_reserved50 (__NR_SVR4 + 187) -#define __NR_SVR4_reserved51 (__NR_SVR4 + 188) -#define __NR_SVR4_reserved52 (__NR_SVR4 + 189) -#define __NR_SVR4_reserved53 (__NR_SVR4 + 190) -#define __NR_SVR4_reserved54 (__NR_SVR4 + 191) -#define __NR_SVR4_reserved55 (__NR_SVR4 + 192) -#define __NR_SVR4_reserved56 (__NR_SVR4 + 193) -#define __NR_SVR4_reserved57 (__NR_SVR4 + 194) -#define __NR_SVR4_reserved58 (__NR_SVR4 + 195) -#define __NR_SVR4_reserved59 (__NR_SVR4 + 196) -#define __NR_SVR4_reserved60 (__NR_SVR4 + 197) -#define __NR_SVR4_reserved61 (__NR_SVR4 + 198) -#define __NR_SVR4_reserved62 (__NR_SVR4 + 199) -#define __NR_SVR4_reserved63 (__NR_SVR4 + 200) -#define __NR_SVR4_aread (__NR_SVR4 + 201) -#define __NR_SVR4_awrite (__NR_SVR4 + 202) -#define __NR_SVR4_listio (__NR_SVR4 + 203) -#define __NR_SVR4_mips_acancel (__NR_SVR4 + 204) -#define __NR_SVR4_astatus (__NR_SVR4 + 205) -#define __NR_SVR4_await (__NR_SVR4 + 206) -#define __NR_SVR4_areadv (__NR_SVR4 + 207) -#define __NR_SVR4_awritev (__NR_SVR4 + 208) -#define __NR_SVR4_MIPS_reserved1 (__NR_SVR4 + 209) -#define __NR_SVR4_MIPS_reserved2 (__NR_SVR4 + 210) -#define __NR_SVR4_MIPS_reserved3 (__NR_SVR4 + 211) -#define __NR_SVR4_MIPS_reserved4 (__NR_SVR4 + 212) -#define __NR_SVR4_MIPS_reserved5 (__NR_SVR4 + 213) -#define __NR_SVR4_MIPS_reserved6 (__NR_SVR4 + 214) -#define __NR_SVR4_MIPS_reserved7 (__NR_SVR4 + 215) -#define __NR_SVR4_MIPS_reserved8 (__NR_SVR4 + 216) -#define __NR_SVR4_MIPS_reserved9 (__NR_SVR4 + 217) -#define __NR_SVR4_MIPS_reserved10 (__NR_SVR4 + 218) -#define __NR_SVR4_MIPS_reserved11 (__NR_SVR4 + 219) -#define __NR_SVR4_MIPS_reserved12 (__NR_SVR4 + 220) -#define __NR_SVR4_CDC_reserved1 (__NR_SVR4 + 221) -#define __NR_SVR4_CDC_reserved2 (__NR_SVR4 + 222) -#define __NR_SVR4_CDC_reserved3 (__NR_SVR4 + 223) -#define __NR_SVR4_CDC_reserved4 (__NR_SVR4 + 224) -#define __NR_SVR4_CDC_reserved5 (__NR_SVR4 + 225) -#define __NR_SVR4_CDC_reserved6 (__NR_SVR4 + 226) -#define __NR_SVR4_CDC_reserved7 (__NR_SVR4 + 227) -#define __NR_SVR4_CDC_reserved8 (__NR_SVR4 + 228) -#define __NR_SVR4_CDC_reserved9 (__NR_SVR4 + 229) -#define __NR_SVR4_CDC_reserved10 (__NR_SVR4 + 230) -#define __NR_SVR4_CDC_reserved11 (__NR_SVR4 + 231) -#define __NR_SVR4_CDC_reserved12 (__NR_SVR4 + 232) -#define __NR_SVR4_CDC_reserved13 (__NR_SVR4 + 233) -#define __NR_SVR4_CDC_reserved14 (__NR_SVR4 + 234) -#define __NR_SVR4_CDC_reserved15 (__NR_SVR4 + 235) -#define __NR_SVR4_CDC_reserved16 (__NR_SVR4 + 236) -#define __NR_SVR4_CDC_reserved17 (__NR_SVR4 + 237) -#define __NR_SVR4_CDC_reserved18 (__NR_SVR4 + 238) -#define __NR_SVR4_CDC_reserved19 (__NR_SVR4 + 239) -#define __NR_SVR4_CDC_reserved20 (__NR_SVR4 + 240) - -/* - * SYS V syscalls are in the range from 1000 to 1999 - */ -#define __NR_SYSV 1000 -#define __NR_SYSV_syscall (__NR_SYSV + 0) -#define __NR_SYSV_exit (__NR_SYSV + 1) -#define __NR_SYSV_fork (__NR_SYSV + 2) -#define __NR_SYSV_read (__NR_SYSV + 3) -#define __NR_SYSV_write (__NR_SYSV + 4) -#define __NR_SYSV_open (__NR_SYSV + 5) -#define __NR_SYSV_close (__NR_SYSV + 6) -#define __NR_SYSV_wait (__NR_SYSV + 7) -#define __NR_SYSV_creat (__NR_SYSV + 8) -#define __NR_SYSV_link (__NR_SYSV + 9) -#define __NR_SYSV_unlink (__NR_SYSV + 10) -#define __NR_SYSV_execv (__NR_SYSV + 11) -#define __NR_SYSV_chdir (__NR_SYSV + 12) -#define __NR_SYSV_time (__NR_SYSV + 13) -#define __NR_SYSV_mknod (__NR_SYSV + 14) -#define __NR_SYSV_chmod (__NR_SYSV + 15) -#define __NR_SYSV_chown (__NR_SYSV + 16) -#define __NR_SYSV_brk (__NR_SYSV + 17) -#define __NR_SYSV_stat (__NR_SYSV + 18) -#define __NR_SYSV_lseek (__NR_SYSV + 19) -#define __NR_SYSV_getpid (__NR_SYSV + 20) -#define __NR_SYSV_mount (__NR_SYSV + 21) -#define __NR_SYSV_umount (__NR_SYSV + 22) -#define __NR_SYSV_setuid (__NR_SYSV + 23) -#define __NR_SYSV_getuid (__NR_SYSV + 24) -#define __NR_SYSV_stime (__NR_SYSV + 25) -#define __NR_SYSV_ptrace (__NR_SYSV + 26) -#define __NR_SYSV_alarm (__NR_SYSV + 27) -#define __NR_SYSV_fstat (__NR_SYSV + 28) -#define __NR_SYSV_pause (__NR_SYSV + 29) -#define __NR_SYSV_utime (__NR_SYSV + 30) -#define __NR_SYSV_stty (__NR_SYSV + 31) -#define __NR_SYSV_gtty (__NR_SYSV + 32) -#define __NR_SYSV_access (__NR_SYSV + 33) -#define __NR_SYSV_nice (__NR_SYSV + 34) -#define __NR_SYSV_statfs (__NR_SYSV + 35) -#define __NR_SYSV_sync (__NR_SYSV + 36) -#define __NR_SYSV_kill (__NR_SYSV + 37) -#define __NR_SYSV_fstatfs (__NR_SYSV + 38) -#define __NR_SYSV_setpgrp (__NR_SYSV + 39) -#define __NR_SYSV_syssgi (__NR_SYSV + 40) -#define __NR_SYSV_dup (__NR_SYSV + 41) -#define __NR_SYSV_pipe (__NR_SYSV + 42) -#define __NR_SYSV_times (__NR_SYSV + 43) -#define __NR_SYSV_profil (__NR_SYSV + 44) -#define __NR_SYSV_plock (__NR_SYSV + 45) -#define __NR_SYSV_setgid (__NR_SYSV + 46) -#define __NR_SYSV_getgid (__NR_SYSV + 47) -#define __NR_SYSV_sig (__NR_SYSV + 48) -#define __NR_SYSV_msgsys (__NR_SYSV + 49) -#define __NR_SYSV_sysmips (__NR_SYSV + 50) -#define __NR_SYSV_acct (__NR_SYSV + 51) -#define __NR_SYSV_shmsys (__NR_SYSV + 52) -#define __NR_SYSV_semsys (__NR_SYSV + 53) -#define __NR_SYSV_ioctl (__NR_SYSV + 54) -#define __NR_SYSV_uadmin (__NR_SYSV + 55) -#define __NR_SYSV_sysmp (__NR_SYSV + 56) -#define __NR_SYSV_utssys (__NR_SYSV + 57) -#define __NR_SYSV_USG_reserved1 (__NR_SYSV + 58) -#define __NR_SYSV_execve (__NR_SYSV + 59) -#define __NR_SYSV_umask (__NR_SYSV + 60) -#define __NR_SYSV_chroot (__NR_SYSV + 61) -#define __NR_SYSV_fcntl (__NR_SYSV + 62) -#define __NR_SYSV_ulimit (__NR_SYSV + 63) -#define __NR_SYSV_SAFARI4_reserved1 (__NR_SYSV + 64) -#define __NR_SYSV_SAFARI4_reserved2 (__NR_SYSV + 65) -#define __NR_SYSV_SAFARI4_reserved3 (__NR_SYSV + 66) -#define __NR_SYSV_SAFARI4_reserved4 (__NR_SYSV + 67) -#define __NR_SYSV_SAFARI4_reserved5 (__NR_SYSV + 68) -#define __NR_SYSV_SAFARI4_reserved6 (__NR_SYSV + 69) -#define __NR_SYSV_advfs (__NR_SYSV + 70) -#define __NR_SYSV_unadvfs (__NR_SYSV + 71) -#define __NR_SYSV_rmount (__NR_SYSV + 72) -#define __NR_SYSV_rumount (__NR_SYSV + 73) -#define __NR_SYSV_rfstart (__NR_SYSV + 74) -#define __NR_SYSV_getrlimit64 (__NR_SYSV + 75) -#define __NR_SYSV_setrlimit64 (__NR_SYSV + 76) -#define __NR_SYSV_nanosleep (__NR_SYSV + 77) -#define __NR_SYSV_lseek64 (__NR_SYSV + 78) -#define __NR_SYSV_rmdir (__NR_SYSV + 79) -#define __NR_SYSV_mkdir (__NR_SYSV + 80) -#define __NR_SYSV_getdents (__NR_SYSV + 81) -#define __NR_SYSV_sginap (__NR_SYSV + 82) -#define __NR_SYSV_sgikopt (__NR_SYSV + 83) -#define __NR_SYSV_sysfs (__NR_SYSV + 84) -#define __NR_SYSV_getmsg (__NR_SYSV + 85) -#define __NR_SYSV_putmsg (__NR_SYSV + 86) -#define __NR_SYSV_poll (__NR_SYSV + 87) -#define __NR_SYSV_sigreturn (__NR_SYSV + 88) -#define __NR_SYSV_accept (__NR_SYSV + 89) -#define __NR_SYSV_bind (__NR_SYSV + 90) -#define __NR_SYSV_connect (__NR_SYSV + 91) -#define __NR_SYSV_gethostid (__NR_SYSV + 92) -#define __NR_SYSV_getpeername (__NR_SYSV + 93) -#define __NR_SYSV_getsockname (__NR_SYSV + 94) -#define __NR_SYSV_getsockopt (__NR_SYSV + 95) -#define __NR_SYSV_listen (__NR_SYSV + 96) -#define __NR_SYSV_recv (__NR_SYSV + 97) -#define __NR_SYSV_recvfrom (__NR_SYSV + 98) -#define __NR_SYSV_recvmsg (__NR_SYSV + 99) -#define __NR_SYSV_select (__NR_SYSV + 100) -#define __NR_SYSV_send (__NR_SYSV + 101) -#define __NR_SYSV_sendmsg (__NR_SYSV + 102) -#define __NR_SYSV_sendto (__NR_SYSV + 103) -#define __NR_SYSV_sethostid (__NR_SYSV + 104) -#define __NR_SYSV_setsockopt (__NR_SYSV + 105) -#define __NR_SYSV_shutdown (__NR_SYSV + 106) -#define __NR_SYSV_socket (__NR_SYSV + 107) -#define __NR_SYSV_gethostname (__NR_SYSV + 108) -#define __NR_SYSV_sethostname (__NR_SYSV + 109) -#define __NR_SYSV_getdomainname (__NR_SYSV + 110) -#define __NR_SYSV_setdomainname (__NR_SYSV + 111) -#define __NR_SYSV_truncate (__NR_SYSV + 112) -#define __NR_SYSV_ftruncate (__NR_SYSV + 113) -#define __NR_SYSV_rename (__NR_SYSV + 114) -#define __NR_SYSV_symlink (__NR_SYSV + 115) -#define __NR_SYSV_readlink (__NR_SYSV + 116) -#define __NR_SYSV_lstat (__NR_SYSV + 117) -#define __NR_SYSV_nfsmount (__NR_SYSV + 118) -#define __NR_SYSV_nfssvc (__NR_SYSV + 119) -#define __NR_SYSV_getfh (__NR_SYSV + 120) -#define __NR_SYSV_async_daemon (__NR_SYSV + 121) -#define __NR_SYSV_exportfs (__NR_SYSV + 122) -#define __NR_SYSV_setregid (__NR_SYSV + 123) -#define __NR_SYSV_setreuid (__NR_SYSV + 124) -#define __NR_SYSV_getitimer (__NR_SYSV + 125) -#define __NR_SYSV_setitimer (__NR_SYSV + 126) -#define __NR_SYSV_adjtime (__NR_SYSV + 127) -#define __NR_SYSV_BSD_getime (__NR_SYSV + 128) -#define __NR_SYSV_sproc (__NR_SYSV + 129) -#define __NR_SYSV_prctl (__NR_SYSV + 130) -#define __NR_SYSV_procblk (__NR_SYSV + 131) -#define __NR_SYSV_sprocsp (__NR_SYSV + 132) -#define __NR_SYSV_sgigsc (__NR_SYSV + 133) -#define __NR_SYSV_mmap (__NR_SYSV + 134) -#define __NR_SYSV_munmap (__NR_SYSV + 135) -#define __NR_SYSV_mprotect (__NR_SYSV + 136) -#define __NR_SYSV_msync (__NR_SYSV + 137) -#define __NR_SYSV_madvise (__NR_SYSV + 138) -#define __NR_SYSV_pagelock (__NR_SYSV + 139) -#define __NR_SYSV_getpagesize (__NR_SYSV + 140) -#define __NR_SYSV_quotactl (__NR_SYSV + 141) -#define __NR_SYSV_libdetach (__NR_SYSV + 142) -#define __NR_SYSV_BSDgetpgrp (__NR_SYSV + 143) -#define __NR_SYSV_BSDsetpgrp (__NR_SYSV + 144) -#define __NR_SYSV_vhangup (__NR_SYSV + 145) -#define __NR_SYSV_fsync (__NR_SYSV + 146) -#define __NR_SYSV_fchdir (__NR_SYSV + 147) -#define __NR_SYSV_getrlimit (__NR_SYSV + 148) -#define __NR_SYSV_setrlimit (__NR_SYSV + 149) -#define __NR_SYSV_cacheflush (__NR_SYSV + 150) -#define __NR_SYSV_cachectl (__NR_SYSV + 151) -#define __NR_SYSV_fchown (__NR_SYSV + 152) -#define __NR_SYSV_fchmod (__NR_SYSV + 153) -#define __NR_SYSV_wait3 (__NR_SYSV + 154) -#define __NR_SYSV_socketpair (__NR_SYSV + 155) -#define __NR_SYSV_sysinfo (__NR_SYSV + 156) -#define __NR_SYSV_nuname (__NR_SYSV + 157) -#define __NR_SYSV_xstat (__NR_SYSV + 158) -#define __NR_SYSV_lxstat (__NR_SYSV + 159) -#define __NR_SYSV_fxstat (__NR_SYSV + 160) -#define __NR_SYSV_xmknod (__NR_SYSV + 161) -#define __NR_SYSV_ksigaction (__NR_SYSV + 162) -#define __NR_SYSV_sigpending (__NR_SYSV + 163) -#define __NR_SYSV_sigprocmask (__NR_SYSV + 164) -#define __NR_SYSV_sigsuspend (__NR_SYSV + 165) -#define __NR_SYSV_sigpoll (__NR_SYSV + 166) -#define __NR_SYSV_swapctl (__NR_SYSV + 167) -#define __NR_SYSV_getcontext (__NR_SYSV + 168) -#define __NR_SYSV_setcontext (__NR_SYSV + 169) -#define __NR_SYSV_waitsys (__NR_SYSV + 170) -#define __NR_SYSV_sigstack (__NR_SYSV + 171) -#define __NR_SYSV_sigaltstack (__NR_SYSV + 172) -#define __NR_SYSV_sigsendset (__NR_SYSV + 173) -#define __NR_SYSV_statvfs (__NR_SYSV + 174) -#define __NR_SYSV_fstatvfs (__NR_SYSV + 175) -#define __NR_SYSV_getpmsg (__NR_SYSV + 176) -#define __NR_SYSV_putpmsg (__NR_SYSV + 177) -#define __NR_SYSV_lchown (__NR_SYSV + 178) -#define __NR_SYSV_priocntl (__NR_SYSV + 179) -#define __NR_SYSV_ksigqueue (__NR_SYSV + 180) -#define __NR_SYSV_readv (__NR_SYSV + 181) -#define __NR_SYSV_writev (__NR_SYSV + 182) -#define __NR_SYSV_truncate64 (__NR_SYSV + 183) -#define __NR_SYSV_ftruncate64 (__NR_SYSV + 184) -#define __NR_SYSV_mmap64 (__NR_SYSV + 185) -#define __NR_SYSV_dmi (__NR_SYSV + 186) -#define __NR_SYSV_pread (__NR_SYSV + 187) -#define __NR_SYSV_pwrite (__NR_SYSV + 188) +#ifndef _ASM_UNISTD_H +#define _ASM_UNISTD_H -/* - * BSD 4.3 syscalls are in the range from 2000 to 2999 - */ -#define __NR_BSD43 2000 -#define __NR_BSD43_syscall (__NR_BSD43 + 0) -#define __NR_BSD43_exit (__NR_BSD43 + 1) -#define __NR_BSD43_fork (__NR_BSD43 + 2) -#define __NR_BSD43_read (__NR_BSD43 + 3) -#define __NR_BSD43_write (__NR_BSD43 + 4) -#define __NR_BSD43_open (__NR_BSD43 + 5) -#define __NR_BSD43_close (__NR_BSD43 + 6) -#define __NR_BSD43_wait (__NR_BSD43 + 7) -#define __NR_BSD43_creat (__NR_BSD43 + 8) -#define __NR_BSD43_link (__NR_BSD43 + 9) -#define __NR_BSD43_unlink (__NR_BSD43 + 10) -#define __NR_BSD43_exec (__NR_BSD43 + 11) -#define __NR_BSD43_chdir (__NR_BSD43 + 12) -#define __NR_BSD43_time (__NR_BSD43 + 13) -#define __NR_BSD43_mknod (__NR_BSD43 + 14) -#define __NR_BSD43_chmod (__NR_BSD43 + 15) -#define __NR_BSD43_chown (__NR_BSD43 + 16) -#define __NR_BSD43_sbreak (__NR_BSD43 + 17) -#define __NR_BSD43_oldstat (__NR_BSD43 + 18) -#define __NR_BSD43_lseek (__NR_BSD43 + 19) -#define __NR_BSD43_getpid (__NR_BSD43 + 20) -#define __NR_BSD43_oldmount (__NR_BSD43 + 21) -#define __NR_BSD43_umount (__NR_BSD43 + 22) -#define __NR_BSD43_setuid (__NR_BSD43 + 23) -#define __NR_BSD43_getuid (__NR_BSD43 + 24) -#define __NR_BSD43_stime (__NR_BSD43 + 25) -#define __NR_BSD43_ptrace (__NR_BSD43 + 26) -#define __NR_BSD43_alarm (__NR_BSD43 + 27) -#define __NR_BSD43_oldfstat (__NR_BSD43 + 28) -#define __NR_BSD43_pause (__NR_BSD43 + 29) -#define __NR_BSD43_utime (__NR_BSD43 + 30) -#define __NR_BSD43_stty (__NR_BSD43 + 31) -#define __NR_BSD43_gtty (__NR_BSD43 + 32) -#define __NR_BSD43_access (__NR_BSD43 + 33) -#define __NR_BSD43_nice (__NR_BSD43 + 34) -#define __NR_BSD43_ftime (__NR_BSD43 + 35) -#define __NR_BSD43_sync (__NR_BSD43 + 36) -#define __NR_BSD43_kill (__NR_BSD43 + 37) -#define __NR_BSD43_stat (__NR_BSD43 + 38) -#define __NR_BSD43_oldsetpgrp (__NR_BSD43 + 39) -#define __NR_BSD43_lstat (__NR_BSD43 + 40) -#define __NR_BSD43_dup (__NR_BSD43 + 41) -#define __NR_BSD43_pipe (__NR_BSD43 + 42) -#define __NR_BSD43_times (__NR_BSD43 + 43) -#define __NR_BSD43_profil (__NR_BSD43 + 44) -#define __NR_BSD43_msgsys (__NR_BSD43 + 45) -#define __NR_BSD43_setgid (__NR_BSD43 + 46) -#define __NR_BSD43_getgid (__NR_BSD43 + 47) -#define __NR_BSD43_ssig (__NR_BSD43 + 48) -#define __NR_BSD43_reserved1 (__NR_BSD43 + 49) -#define __NR_BSD43_reserved2 (__NR_BSD43 + 50) -#define __NR_BSD43_sysacct (__NR_BSD43 + 51) -#define __NR_BSD43_phys (__NR_BSD43 + 52) -#define __NR_BSD43_lock (__NR_BSD43 + 53) -#define __NR_BSD43_ioctl (__NR_BSD43 + 54) -#define __NR_BSD43_reboot (__NR_BSD43 + 55) -#define __NR_BSD43_mpxchan (__NR_BSD43 + 56) -#define __NR_BSD43_symlink (__NR_BSD43 + 57) -#define __NR_BSD43_readlink (__NR_BSD43 + 58) -#define __NR_BSD43_execve (__NR_BSD43 + 59) -#define __NR_BSD43_umask (__NR_BSD43 + 60) -#define __NR_BSD43_chroot (__NR_BSD43 + 61) -#define __NR_BSD43_fstat (__NR_BSD43 + 62) -#define __NR_BSD43_reserved3 (__NR_BSD43 + 63) -#define __NR_BSD43_getpagesize (__NR_BSD43 + 64) -#define __NR_BSD43_mremap (__NR_BSD43 + 65) -#define __NR_BSD43_vfork (__NR_BSD43 + 66) -#define __NR_BSD43_vread (__NR_BSD43 + 67) -#define __NR_BSD43_vwrite (__NR_BSD43 + 68) -#define __NR_BSD43_sbrk (__NR_BSD43 + 69) -#define __NR_BSD43_sstk (__NR_BSD43 + 70) -#define __NR_BSD43_mmap (__NR_BSD43 + 71) -#define __NR_BSD43_vadvise (__NR_BSD43 + 72) -#define __NR_BSD43_munmap (__NR_BSD43 + 73) -#define __NR_BSD43_mprotect (__NR_BSD43 + 74) -#define __NR_BSD43_madvise (__NR_BSD43 + 75) -#define __NR_BSD43_vhangup (__NR_BSD43 + 76) -#define __NR_BSD43_vlimit (__NR_BSD43 + 77) -#define __NR_BSD43_mincore (__NR_BSD43 + 78) -#define __NR_BSD43_getgroups (__NR_BSD43 + 79) -#define __NR_BSD43_setgroups (__NR_BSD43 + 80) -#define __NR_BSD43_getpgrp (__NR_BSD43 + 81) -#define __NR_BSD43_setpgrp (__NR_BSD43 + 82) -#define __NR_BSD43_setitimer (__NR_BSD43 + 83) -#define __NR_BSD43_wait3 (__NR_BSD43 + 84) -#define __NR_BSD43_swapon (__NR_BSD43 + 85) -#define __NR_BSD43_getitimer (__NR_BSD43 + 86) -#define __NR_BSD43_gethostname (__NR_BSD43 + 87) -#define __NR_BSD43_sethostname (__NR_BSD43 + 88) -#define __NR_BSD43_getdtablesize (__NR_BSD43 + 89) -#define __NR_BSD43_dup2 (__NR_BSD43 + 90) -#define __NR_BSD43_getdopt (__NR_BSD43 + 91) -#define __NR_BSD43_fcntl (__NR_BSD43 + 92) -#define __NR_BSD43_select (__NR_BSD43 + 93) -#define __NR_BSD43_setdopt (__NR_BSD43 + 94) -#define __NR_BSD43_fsync (__NR_BSD43 + 95) -#define __NR_BSD43_setpriority (__NR_BSD43 + 96) -#define __NR_BSD43_socket (__NR_BSD43 + 97) -#define __NR_BSD43_connect (__NR_BSD43 + 98) -#define __NR_BSD43_oldaccept (__NR_BSD43 + 99) -#define __NR_BSD43_getpriority (__NR_BSD43 + 100) -#define __NR_BSD43_send (__NR_BSD43 + 101) -#define __NR_BSD43_recv (__NR_BSD43 + 102) -#define __NR_BSD43_sigreturn (__NR_BSD43 + 103) -#define __NR_BSD43_bind (__NR_BSD43 + 104) -#define __NR_BSD43_setsockopt (__NR_BSD43 + 105) -#define __NR_BSD43_listen (__NR_BSD43 + 106) -#define __NR_BSD43_vtimes (__NR_BSD43 + 107) -#define __NR_BSD43_sigvec (__NR_BSD43 + 108) -#define __NR_BSD43_sigblock (__NR_BSD43 + 109) -#define __NR_BSD43_sigsetmask (__NR_BSD43 + 110) -#define __NR_BSD43_sigpause (__NR_BSD43 + 111) -#define __NR_BSD43_sigstack (__NR_BSD43 + 112) -#define __NR_BSD43_oldrecvmsg (__NR_BSD43 + 113) -#define __NR_BSD43_oldsendmsg (__NR_BSD43 + 114) -#define __NR_BSD43_vtrace (__NR_BSD43 + 115) -#define __NR_BSD43_gettimeofday (__NR_BSD43 + 116) -#define __NR_BSD43_getrusage (__NR_BSD43 + 117) -#define __NR_BSD43_getsockopt (__NR_BSD43 + 118) -#define __NR_BSD43_reserved4 (__NR_BSD43 + 119) -#define __NR_BSD43_readv (__NR_BSD43 + 120) -#define __NR_BSD43_writev (__NR_BSD43 + 121) -#define __NR_BSD43_settimeofday (__NR_BSD43 + 122) -#define __NR_BSD43_fchown (__NR_BSD43 + 123) -#define __NR_BSD43_fchmod (__NR_BSD43 + 124) -#define __NR_BSD43_oldrecvfrom (__NR_BSD43 + 125) -#define __NR_BSD43_setreuid (__NR_BSD43 + 126) -#define __NR_BSD43_setregid (__NR_BSD43 + 127) -#define __NR_BSD43_rename (__NR_BSD43 + 128) -#define __NR_BSD43_truncate (__NR_BSD43 + 129) -#define __NR_BSD43_ftruncate (__NR_BSD43 + 130) -#define __NR_BSD43_flock (__NR_BSD43 + 131) -#define __NR_BSD43_semsys (__NR_BSD43 + 132) -#define __NR_BSD43_sendto (__NR_BSD43 + 133) -#define __NR_BSD43_shutdown (__NR_BSD43 + 134) -#define __NR_BSD43_socketpair (__NR_BSD43 + 135) -#define __NR_BSD43_mkdir (__NR_BSD43 + 136) -#define __NR_BSD43_rmdir (__NR_BSD43 + 137) -#define __NR_BSD43_utimes (__NR_BSD43 + 138) -#define __NR_BSD43_sigcleanup (__NR_BSD43 + 139) -#define __NR_BSD43_adjtime (__NR_BSD43 + 140) -#define __NR_BSD43_oldgetpeername (__NR_BSD43 + 141) -#define __NR_BSD43_gethostid (__NR_BSD43 + 142) -#define __NR_BSD43_sethostid (__NR_BSD43 + 143) -#define __NR_BSD43_getrlimit (__NR_BSD43 + 144) -#define __NR_BSD43_setrlimit (__NR_BSD43 + 145) -#define __NR_BSD43_killpg (__NR_BSD43 + 146) -#define __NR_BSD43_shmsys (__NR_BSD43 + 147) -#define __NR_BSD43_quota (__NR_BSD43 + 148) -#define __NR_BSD43_qquota (__NR_BSD43 + 149) -#define __NR_BSD43_oldgetsockname (__NR_BSD43 + 150) -#define __NR_BSD43_sysmips (__NR_BSD43 + 151) -#define __NR_BSD43_cacheflush (__NR_BSD43 + 152) -#define __NR_BSD43_cachectl (__NR_BSD43 + 153) -#define __NR_BSD43_debug (__NR_BSD43 + 154) -#define __NR_BSD43_reserved5 (__NR_BSD43 + 155) -#define __NR_BSD43_reserved6 (__NR_BSD43 + 156) -#define __NR_BSD43_nfs_mount (__NR_BSD43 + 157) -#define __NR_BSD43_nfs_svc (__NR_BSD43 + 158) -#define __NR_BSD43_getdirentries (__NR_BSD43 + 159) -#define __NR_BSD43_statfs (__NR_BSD43 + 160) -#define __NR_BSD43_fstatfs (__NR_BSD43 + 161) -#define __NR_BSD43_unmount (__NR_BSD43 + 162) -#define __NR_BSD43_async_daemon (__NR_BSD43 + 163) -#define __NR_BSD43_nfs_getfh (__NR_BSD43 + 164) -#define __NR_BSD43_getdomainname (__NR_BSD43 + 165) -#define __NR_BSD43_setdomainname (__NR_BSD43 + 166) -#define __NR_BSD43_pcfs_mount (__NR_BSD43 + 167) -#define __NR_BSD43_quotactl (__NR_BSD43 + 168) -#define __NR_BSD43_oldexportfs (__NR_BSD43 + 169) -#define __NR_BSD43_smount (__NR_BSD43 + 170) -#define __NR_BSD43_mipshwconf (__NR_BSD43 + 171) -#define __NR_BSD43_exportfs (__NR_BSD43 + 172) -#define __NR_BSD43_nfsfh_open (__NR_BSD43 + 173) -#define __NR_BSD43_libattach (__NR_BSD43 + 174) -#define __NR_BSD43_libdetach (__NR_BSD43 + 175) -#define __NR_BSD43_accept (__NR_BSD43 + 176) -#define __NR_BSD43_reserved7 (__NR_BSD43 + 177) -#define __NR_BSD43_reserved8 (__NR_BSD43 + 178) -#define __NR_BSD43_recvmsg (__NR_BSD43 + 179) -#define __NR_BSD43_recvfrom (__NR_BSD43 + 180) -#define __NR_BSD43_sendmsg (__NR_BSD43 + 181) -#define __NR_BSD43_getpeername (__NR_BSD43 + 182) -#define __NR_BSD43_getsockname (__NR_BSD43 + 183) -#define __NR_BSD43_aread (__NR_BSD43 + 184) -#define __NR_BSD43_awrite (__NR_BSD43 + 185) -#define __NR_BSD43_listio (__NR_BSD43 + 186) -#define __NR_BSD43_acancel (__NR_BSD43 + 187) -#define __NR_BSD43_astatus (__NR_BSD43 + 188) -#define __NR_BSD43_await (__NR_BSD43 + 189) -#define __NR_BSD43_areadv (__NR_BSD43 + 190) -#define __NR_BSD43_awritev (__NR_BSD43 + 191) - -/* - * POSIX syscalls are in the range from 3000 to 3999 - */ -#define __NR_POSIX 3000 -#define __NR_POSIX_syscall (__NR_POSIX + 0) -#define __NR_POSIX_exit (__NR_POSIX + 1) -#define __NR_POSIX_fork (__NR_POSIX + 2) -#define __NR_POSIX_read (__NR_POSIX + 3) -#define __NR_POSIX_write (__NR_POSIX + 4) -#define __NR_POSIX_open (__NR_POSIX + 5) -#define __NR_POSIX_close (__NR_POSIX + 6) -#define __NR_POSIX_wait (__NR_POSIX + 7) -#define __NR_POSIX_creat (__NR_POSIX + 8) -#define __NR_POSIX_link (__NR_POSIX + 9) -#define __NR_POSIX_unlink (__NR_POSIX + 10) -#define __NR_POSIX_exec (__NR_POSIX + 11) -#define __NR_POSIX_chdir (__NR_POSIX + 12) -#define __NR_POSIX_gtime (__NR_POSIX + 13) -#define __NR_POSIX_mknod (__NR_POSIX + 14) -#define __NR_POSIX_chmod (__NR_POSIX + 15) -#define __NR_POSIX_chown (__NR_POSIX + 16) -#define __NR_POSIX_sbreak (__NR_POSIX + 17) -#define __NR_POSIX_stat (__NR_POSIX + 18) -#define __NR_POSIX_lseek (__NR_POSIX + 19) -#define __NR_POSIX_getpid (__NR_POSIX + 20) -#define __NR_POSIX_mount (__NR_POSIX + 21) -#define __NR_POSIX_umount (__NR_POSIX + 22) -#define __NR_POSIX_setuid (__NR_POSIX + 23) -#define __NR_POSIX_getuid (__NR_POSIX + 24) -#define __NR_POSIX_stime (__NR_POSIX + 25) -#define __NR_POSIX_ptrace (__NR_POSIX + 26) -#define __NR_POSIX_alarm (__NR_POSIX + 27) -#define __NR_POSIX_fstat (__NR_POSIX + 28) -#define __NR_POSIX_pause (__NR_POSIX + 29) -#define __NR_POSIX_utime (__NR_POSIX + 30) -#define __NR_POSIX_stty (__NR_POSIX + 31) -#define __NR_POSIX_gtty (__NR_POSIX + 32) -#define __NR_POSIX_access (__NR_POSIX + 33) -#define __NR_POSIX_nice (__NR_POSIX + 34) -#define __NR_POSIX_statfs (__NR_POSIX + 35) -#define __NR_POSIX_sync (__NR_POSIX + 36) -#define __NR_POSIX_kill (__NR_POSIX + 37) -#define __NR_POSIX_fstatfs (__NR_POSIX + 38) -#define __NR_POSIX_getpgrp (__NR_POSIX + 39) -#define __NR_POSIX_syssgi (__NR_POSIX + 40) -#define __NR_POSIX_dup (__NR_POSIX + 41) -#define __NR_POSIX_pipe (__NR_POSIX + 42) -#define __NR_POSIX_times (__NR_POSIX + 43) -#define __NR_POSIX_profil (__NR_POSIX + 44) -#define __NR_POSIX_lock (__NR_POSIX + 45) -#define __NR_POSIX_setgid (__NR_POSIX + 46) -#define __NR_POSIX_getgid (__NR_POSIX + 47) -#define __NR_POSIX_sig (__NR_POSIX + 48) -#define __NR_POSIX_msgsys (__NR_POSIX + 49) -#define __NR_POSIX_sysmips (__NR_POSIX + 50) -#define __NR_POSIX_sysacct (__NR_POSIX + 51) -#define __NR_POSIX_shmsys (__NR_POSIX + 52) -#define __NR_POSIX_semsys (__NR_POSIX + 53) -#define __NR_POSIX_ioctl (__NR_POSIX + 54) -#define __NR_POSIX_uadmin (__NR_POSIX + 55) -#define __NR_POSIX_exch (__NR_POSIX + 56) -#define __NR_POSIX_utssys (__NR_POSIX + 57) -#define __NR_POSIX_USG_reserved1 (__NR_POSIX + 58) -#define __NR_POSIX_exece (__NR_POSIX + 59) -#define __NR_POSIX_umask (__NR_POSIX + 60) -#define __NR_POSIX_chroot (__NR_POSIX + 61) -#define __NR_POSIX_fcntl (__NR_POSIX + 62) -#define __NR_POSIX_ulimit (__NR_POSIX + 63) -#define __NR_POSIX_SAFARI4_reserved1 (__NR_POSIX + 64) -#define __NR_POSIX_SAFARI4_reserved2 (__NR_POSIX + 65) -#define __NR_POSIX_SAFARI4_reserved3 (__NR_POSIX + 66) -#define __NR_POSIX_SAFARI4_reserved4 (__NR_POSIX + 67) -#define __NR_POSIX_SAFARI4_reserved5 (__NR_POSIX + 68) -#define __NR_POSIX_SAFARI4_reserved6 (__NR_POSIX + 69) -#define __NR_POSIX_advfs (__NR_POSIX + 70) -#define __NR_POSIX_unadvfs (__NR_POSIX + 71) -#define __NR_POSIX_rmount (__NR_POSIX + 72) -#define __NR_POSIX_rumount (__NR_POSIX + 73) -#define __NR_POSIX_rfstart (__NR_POSIX + 74) -#define __NR_POSIX_reserved1 (__NR_POSIX + 75) -#define __NR_POSIX_rdebug (__NR_POSIX + 76) -#define __NR_POSIX_rfstop (__NR_POSIX + 77) -#define __NR_POSIX_rfsys (__NR_POSIX + 78) -#define __NR_POSIX_rmdir (__NR_POSIX + 79) -#define __NR_POSIX_mkdir (__NR_POSIX + 80) -#define __NR_POSIX_getdents (__NR_POSIX + 81) -#define __NR_POSIX_sginap (__NR_POSIX + 82) -#define __NR_POSIX_sgikopt (__NR_POSIX + 83) -#define __NR_POSIX_sysfs (__NR_POSIX + 84) -#define __NR_POSIX_getmsg (__NR_POSIX + 85) -#define __NR_POSIX_putmsg (__NR_POSIX + 86) -#define __NR_POSIX_poll (__NR_POSIX + 87) -#define __NR_POSIX_sigreturn (__NR_POSIX + 88) -#define __NR_POSIX_accept (__NR_POSIX + 89) -#define __NR_POSIX_bind (__NR_POSIX + 90) -#define __NR_POSIX_connect (__NR_POSIX + 91) -#define __NR_POSIX_gethostid (__NR_POSIX + 92) -#define __NR_POSIX_getpeername (__NR_POSIX + 93) -#define __NR_POSIX_getsockname (__NR_POSIX + 94) -#define __NR_POSIX_getsockopt (__NR_POSIX + 95) -#define __NR_POSIX_listen (__NR_POSIX + 96) -#define __NR_POSIX_recv (__NR_POSIX + 97) -#define __NR_POSIX_recvfrom (__NR_POSIX + 98) -#define __NR_POSIX_recvmsg (__NR_POSIX + 99) -#define __NR_POSIX_select (__NR_POSIX + 100) -#define __NR_POSIX_send (__NR_POSIX + 101) -#define __NR_POSIX_sendmsg (__NR_POSIX + 102) -#define __NR_POSIX_sendto (__NR_POSIX + 103) -#define __NR_POSIX_sethostid (__NR_POSIX + 104) -#define __NR_POSIX_setsockopt (__NR_POSIX + 105) -#define __NR_POSIX_shutdown (__NR_POSIX + 106) -#define __NR_POSIX_socket (__NR_POSIX + 107) -#define __NR_POSIX_gethostname (__NR_POSIX + 108) -#define __NR_POSIX_sethostname (__NR_POSIX + 109) -#define __NR_POSIX_getdomainname (__NR_POSIX + 110) -#define __NR_POSIX_setdomainname (__NR_POSIX + 111) -#define __NR_POSIX_truncate (__NR_POSIX + 112) -#define __NR_POSIX_ftruncate (__NR_POSIX + 113) -#define __NR_POSIX_rename (__NR_POSIX + 114) -#define __NR_POSIX_symlink (__NR_POSIX + 115) -#define __NR_POSIX_readlink (__NR_POSIX + 116) -#define __NR_POSIX_lstat (__NR_POSIX + 117) -#define __NR_POSIX_nfs_mount (__NR_POSIX + 118) -#define __NR_POSIX_nfs_svc (__NR_POSIX + 119) -#define __NR_POSIX_nfs_getfh (__NR_POSIX + 120) -#define __NR_POSIX_async_daemon (__NR_POSIX + 121) -#define __NR_POSIX_exportfs (__NR_POSIX + 122) -#define __NR_POSIX_SGI_setregid (__NR_POSIX + 123) -#define __NR_POSIX_SGI_setreuid (__NR_POSIX + 124) -#define __NR_POSIX_getitimer (__NR_POSIX + 125) -#define __NR_POSIX_setitimer (__NR_POSIX + 126) -#define __NR_POSIX_adjtime (__NR_POSIX + 127) -#define __NR_POSIX_SGI_bsdgettime (__NR_POSIX + 128) -#define __NR_POSIX_SGI_sproc (__NR_POSIX + 129) -#define __NR_POSIX_SGI_prctl (__NR_POSIX + 130) -#define __NR_POSIX_SGI_blkproc (__NR_POSIX + 131) -#define __NR_POSIX_SGI_reserved1 (__NR_POSIX + 132) -#define __NR_POSIX_SGI_sgigsc (__NR_POSIX + 133) -#define __NR_POSIX_SGI_mmap (__NR_POSIX + 134) -#define __NR_POSIX_SGI_munmap (__NR_POSIX + 135) -#define __NR_POSIX_SGI_mprotect (__NR_POSIX + 136) -#define __NR_POSIX_SGI_msync (__NR_POSIX + 137) -#define __NR_POSIX_SGI_madvise (__NR_POSIX + 138) -#define __NR_POSIX_SGI_mpin (__NR_POSIX + 139) -#define __NR_POSIX_SGI_getpagesize (__NR_POSIX + 140) -#define __NR_POSIX_SGI_libattach (__NR_POSIX + 141) -#define __NR_POSIX_SGI_libdetach (__NR_POSIX + 142) -#define __NR_POSIX_SGI_getpgrp (__NR_POSIX + 143) -#define __NR_POSIX_SGI_setpgrp (__NR_POSIX + 144) -#define __NR_POSIX_SGI_reserved2 (__NR_POSIX + 145) -#define __NR_POSIX_SGI_reserved3 (__NR_POSIX + 146) -#define __NR_POSIX_SGI_reserved4 (__NR_POSIX + 147) -#define __NR_POSIX_SGI_reserved5 (__NR_POSIX + 148) -#define __NR_POSIX_SGI_reserved6 (__NR_POSIX + 149) -#define __NR_POSIX_cacheflush (__NR_POSIX + 150) -#define __NR_POSIX_cachectl (__NR_POSIX + 151) -#define __NR_POSIX_fchown (__NR_POSIX + 152) -#define __NR_POSIX_fchmod (__NR_POSIX + 153) -#define __NR_POSIX_wait3 (__NR_POSIX + 154) -#define __NR_POSIX_mmap (__NR_POSIX + 155) -#define __NR_POSIX_munmap (__NR_POSIX + 156) -#define __NR_POSIX_madvise (__NR_POSIX + 157) -#define __NR_POSIX_BSD_getpagesize (__NR_POSIX + 158) -#define __NR_POSIX_setreuid (__NR_POSIX + 159) -#define __NR_POSIX_setregid (__NR_POSIX + 160) -#define __NR_POSIX_setpgid (__NR_POSIX + 161) -#define __NR_POSIX_getgroups (__NR_POSIX + 162) -#define __NR_POSIX_setgroups (__NR_POSIX + 163) -#define __NR_POSIX_gettimeofday (__NR_POSIX + 164) -#define __NR_POSIX_getrusage (__NR_POSIX + 165) -#define __NR_POSIX_getrlimit (__NR_POSIX + 166) -#define __NR_POSIX_setrlimit (__NR_POSIX + 167) -#define __NR_POSIX_waitpid (__NR_POSIX + 168) -#define __NR_POSIX_dup2 (__NR_POSIX + 169) -#define __NR_POSIX_reserved2 (__NR_POSIX + 170) -#define __NR_POSIX_reserved3 (__NR_POSIX + 171) -#define __NR_POSIX_reserved4 (__NR_POSIX + 172) -#define __NR_POSIX_reserved5 (__NR_POSIX + 173) -#define __NR_POSIX_reserved6 (__NR_POSIX + 174) -#define __NR_POSIX_reserved7 (__NR_POSIX + 175) -#define __NR_POSIX_reserved8 (__NR_POSIX + 176) -#define __NR_POSIX_reserved9 (__NR_POSIX + 177) -#define __NR_POSIX_reserved10 (__NR_POSIX + 178) -#define __NR_POSIX_reserved11 (__NR_POSIX + 179) -#define __NR_POSIX_reserved12 (__NR_POSIX + 180) -#define __NR_POSIX_reserved13 (__NR_POSIX + 181) -#define __NR_POSIX_reserved14 (__NR_POSIX + 182) -#define __NR_POSIX_reserved15 (__NR_POSIX + 183) -#define __NR_POSIX_reserved16 (__NR_POSIX + 184) -#define __NR_POSIX_reserved17 (__NR_POSIX + 185) -#define __NR_POSIX_reserved18 (__NR_POSIX + 186) -#define __NR_POSIX_reserved19 (__NR_POSIX + 187) -#define __NR_POSIX_reserved20 (__NR_POSIX + 188) -#define __NR_POSIX_reserved21 (__NR_POSIX + 189) -#define __NR_POSIX_reserved22 (__NR_POSIX + 190) -#define __NR_POSIX_reserved23 (__NR_POSIX + 191) -#define __NR_POSIX_reserved24 (__NR_POSIX + 192) -#define __NR_POSIX_reserved25 (__NR_POSIX + 193) -#define __NR_POSIX_reserved26 (__NR_POSIX + 194) -#define __NR_POSIX_reserved27 (__NR_POSIX + 195) -#define __NR_POSIX_reserved28 (__NR_POSIX + 196) -#define __NR_POSIX_reserved29 (__NR_POSIX + 197) -#define __NR_POSIX_reserved30 (__NR_POSIX + 198) -#define __NR_POSIX_reserved31 (__NR_POSIX + 199) -#define __NR_POSIX_reserved32 (__NR_POSIX + 200) -#define __NR_POSIX_reserved33 (__NR_POSIX + 201) -#define __NR_POSIX_reserved34 (__NR_POSIX + 202) -#define __NR_POSIX_reserved35 (__NR_POSIX + 203) -#define __NR_POSIX_reserved36 (__NR_POSIX + 204) -#define __NR_POSIX_reserved37 (__NR_POSIX + 205) -#define __NR_POSIX_reserved38 (__NR_POSIX + 206) -#define __NR_POSIX_reserved39 (__NR_POSIX + 207) -#define __NR_POSIX_reserved40 (__NR_POSIX + 208) -#define __NR_POSIX_reserved41 (__NR_POSIX + 209) -#define __NR_POSIX_reserved42 (__NR_POSIX + 210) -#define __NR_POSIX_reserved43 (__NR_POSIX + 211) -#define __NR_POSIX_reserved44 (__NR_POSIX + 212) -#define __NR_POSIX_reserved45 (__NR_POSIX + 213) -#define __NR_POSIX_reserved46 (__NR_POSIX + 214) -#define __NR_POSIX_reserved47 (__NR_POSIX + 215) -#define __NR_POSIX_reserved48 (__NR_POSIX + 216) -#define __NR_POSIX_reserved49 (__NR_POSIX + 217) -#define __NR_POSIX_reserved50 (__NR_POSIX + 218) -#define __NR_POSIX_reserved51 (__NR_POSIX + 219) -#define __NR_POSIX_reserved52 (__NR_POSIX + 220) -#define __NR_POSIX_reserved53 (__NR_POSIX + 221) -#define __NR_POSIX_reserved54 (__NR_POSIX + 222) -#define __NR_POSIX_reserved55 (__NR_POSIX + 223) -#define __NR_POSIX_reserved56 (__NR_POSIX + 224) -#define __NR_POSIX_reserved57 (__NR_POSIX + 225) -#define __NR_POSIX_reserved58 (__NR_POSIX + 226) -#define __NR_POSIX_reserved59 (__NR_POSIX + 227) -#define __NR_POSIX_reserved60 (__NR_POSIX + 228) -#define __NR_POSIX_reserved61 (__NR_POSIX + 229) -#define __NR_POSIX_reserved62 (__NR_POSIX + 230) -#define __NR_POSIX_reserved63 (__NR_POSIX + 231) -#define __NR_POSIX_reserved64 (__NR_POSIX + 232) -#define __NR_POSIX_reserved65 (__NR_POSIX + 233) -#define __NR_POSIX_reserved66 (__NR_POSIX + 234) -#define __NR_POSIX_reserved67 (__NR_POSIX + 235) -#define __NR_POSIX_reserved68 (__NR_POSIX + 236) -#define __NR_POSIX_reserved69 (__NR_POSIX + 237) -#define __NR_POSIX_reserved70 (__NR_POSIX + 238) -#define __NR_POSIX_reserved71 (__NR_POSIX + 239) -#define __NR_POSIX_reserved72 (__NR_POSIX + 240) -#define __NR_POSIX_reserved73 (__NR_POSIX + 241) -#define __NR_POSIX_reserved74 (__NR_POSIX + 242) -#define __NR_POSIX_reserved75 (__NR_POSIX + 243) -#define __NR_POSIX_reserved76 (__NR_POSIX + 244) -#define __NR_POSIX_reserved77 (__NR_POSIX + 245) -#define __NR_POSIX_reserved78 (__NR_POSIX + 246) -#define __NR_POSIX_reserved79 (__NR_POSIX + 247) -#define __NR_POSIX_reserved80 (__NR_POSIX + 248) -#define __NR_POSIX_reserved81 (__NR_POSIX + 249) -#define __NR_POSIX_reserved82 (__NR_POSIX + 250) -#define __NR_POSIX_reserved83 (__NR_POSIX + 251) -#define __NR_POSIX_reserved84 (__NR_POSIX + 252) -#define __NR_POSIX_reserved85 (__NR_POSIX + 253) -#define __NR_POSIX_reserved86 (__NR_POSIX + 254) -#define __NR_POSIX_reserved87 (__NR_POSIX + 255) -#define __NR_POSIX_reserved88 (__NR_POSIX + 256) -#define __NR_POSIX_reserved89 (__NR_POSIX + 257) -#define __NR_POSIX_reserved90 (__NR_POSIX + 258) -#define __NR_POSIX_reserved91 (__NR_POSIX + 259) -#define __NR_POSIX_netboot (__NR_POSIX + 260) -#define __NR_POSIX_netunboot (__NR_POSIX + 261) -#define __NR_POSIX_rdump (__NR_POSIX + 262) -#define __NR_POSIX_setsid (__NR_POSIX + 263) -#define __NR_POSIX_getmaxsig (__NR_POSIX + 264) -#define __NR_POSIX_sigpending (__NR_POSIX + 265) -#define __NR_POSIX_sigprocmask (__NR_POSIX + 266) -#define __NR_POSIX_sigsuspend (__NR_POSIX + 267) -#define __NR_POSIX_sigaction (__NR_POSIX + 268) -#define __NR_POSIX_MIPS_reserved1 (__NR_POSIX + 269) -#define __NR_POSIX_MIPS_reserved2 (__NR_POSIX + 270) -#define __NR_POSIX_MIPS_reserved3 (__NR_POSIX + 271) -#define __NR_POSIX_MIPS_reserved4 (__NR_POSIX + 272) -#define __NR_POSIX_MIPS_reserved5 (__NR_POSIX + 273) -#define __NR_POSIX_MIPS_reserved6 (__NR_POSIX + 274) -#define __NR_POSIX_MIPS_reserved7 (__NR_POSIX + 275) -#define __NR_POSIX_MIPS_reserved8 (__NR_POSIX + 276) -#define __NR_POSIX_MIPS_reserved9 (__NR_POSIX + 277) -#define __NR_POSIX_MIPS_reserved10 (__NR_POSIX + 278) -#define __NR_POSIX_MIPS_reserved11 (__NR_POSIX + 279) -#define __NR_POSIX_TANDEM_reserved1 (__NR_POSIX + 280) -#define __NR_POSIX_TANDEM_reserved2 (__NR_POSIX + 281) -#define __NR_POSIX_TANDEM_reserved3 (__NR_POSIX + 282) -#define __NR_POSIX_TANDEM_reserved4 (__NR_POSIX + 283) -#define __NR_POSIX_TANDEM_reserved5 (__NR_POSIX + 284) -#define __NR_POSIX_TANDEM_reserved6 (__NR_POSIX + 285) -#define __NR_POSIX_TANDEM_reserved7 (__NR_POSIX + 286) -#define __NR_POSIX_TANDEM_reserved8 (__NR_POSIX + 287) -#define __NR_POSIX_TANDEM_reserved9 (__NR_POSIX + 288) -#define __NR_POSIX_TANDEM_reserved10 (__NR_POSIX + 289) -#define __NR_POSIX_TANDEM_reserved11 (__NR_POSIX + 290) -#define __NR_POSIX_TANDEM_reserved12 (__NR_POSIX + 291) -#define __NR_POSIX_TANDEM_reserved13 (__NR_POSIX + 292) -#define __NR_POSIX_TANDEM_reserved14 (__NR_POSIX + 293) -#define __NR_POSIX_TANDEM_reserved15 (__NR_POSIX + 294) -#define __NR_POSIX_TANDEM_reserved16 (__NR_POSIX + 295) -#define __NR_POSIX_TANDEM_reserved17 (__NR_POSIX + 296) -#define __NR_POSIX_TANDEM_reserved18 (__NR_POSIX + 297) -#define __NR_POSIX_TANDEM_reserved19 (__NR_POSIX + 298) -#define __NR_POSIX_TANDEM_reserved20 (__NR_POSIX + 299) -#define __NR_POSIX_SGI_reserved7 (__NR_POSIX + 300) -#define __NR_POSIX_SGI_reserved8 (__NR_POSIX + 301) -#define __NR_POSIX_SGI_reserved9 (__NR_POSIX + 302) -#define __NR_POSIX_SGI_reserved10 (__NR_POSIX + 303) -#define __NR_POSIX_SGI_reserved11 (__NR_POSIX + 304) -#define __NR_POSIX_SGI_reserved12 (__NR_POSIX + 305) -#define __NR_POSIX_SGI_reserved13 (__NR_POSIX + 306) -#define __NR_POSIX_SGI_reserved14 (__NR_POSIX + 307) -#define __NR_POSIX_SGI_reserved15 (__NR_POSIX + 308) -#define __NR_POSIX_SGI_reserved16 (__NR_POSIX + 309) -#define __NR_POSIX_SGI_reserved17 (__NR_POSIX + 310) -#define __NR_POSIX_SGI_reserved18 (__NR_POSIX + 311) -#define __NR_POSIX_SGI_reserved19 (__NR_POSIX + 312) -#define __NR_POSIX_SGI_reserved20 (__NR_POSIX + 313) -#define __NR_POSIX_SGI_reserved21 (__NR_POSIX + 314) -#define __NR_POSIX_SGI_reserved22 (__NR_POSIX + 315) -#define __NR_POSIX_SGI_reserved23 (__NR_POSIX + 316) -#define __NR_POSIX_SGI_reserved24 (__NR_POSIX + 317) -#define __NR_POSIX_SGI_reserved25 (__NR_POSIX + 318) -#define __NR_POSIX_SGI_reserved26 (__NR_POSIX + 319) - -/* - * Linux syscalls are in the range from 4000 to 4999 - * Hopefully these syscall numbers are unused ... If not everyone using - * statically linked binaries is pretty upsh*t. You've been warned. - */ #define __NR_Linux 4000 #define __NR_syscall (__NR_Linux + 0) #define __NR_exit (__NR_Linux + 1) @@ -1045,7 +71,7 @@ #define __NR_mpx (__NR_Linux + 56) #define __NR_setpgid (__NR_Linux + 57) #define __NR_ulimit (__NR_Linux + 58) -#define __NR_oldolduname (__NR_Linux + 59) +#define __NR_unused59 (__NR_Linux + 59) #define __NR_umask (__NR_Linux + 60) #define __NR_chroot (__NR_Linux + 61) #define __NR_ustat (__NR_Linux + 62) @@ -1095,7 +121,7 @@ #define __NR_stat (__NR_Linux + 106) #define __NR_lstat (__NR_Linux + 107) #define __NR_fstat (__NR_Linux + 108) -#define __NR_olduname (__NR_Linux + 109) +#define __NR_unused109 (__NR_Linux + 109) #define __NR_iopl (__NR_Linux + 110) #define __NR_vhangup (__NR_Linux + 111) #define __NR_idle (__NR_Linux + 112) @@ -1206,11 +232,12 @@ #define __NR_mincore (__NR_Linux + 217) #define __NR_madvise (__NR_Linux + 218) #define __NR_getdents64 (__NR_Linux + 219) +#define __NR_fcntl64 (__NR_Linux + 220) /* * Offset of the last Linux flavoured syscall */ -#define __NR_Linux_syscalls 219 +#define __NR_Linux_syscalls 220 #ifndef _LANGUAGE_ASSEMBLY @@ -1218,13 +245,15 @@ #define _syscall0(type,name) \ type name(void) \ { \ -register long __res __asm__ ("$2"); \ -register long __err __asm__ ("$7"); \ +long __res, __err; \ __asm__ volatile ("li\t$2,%2\n\t" \ - "syscall" \ + "syscall\n\t" \ + "move\t%0, $2\n\t" \ + "move\t%1, $7" \ : "=r" (__res), "=r" (__err) \ : "i" (__NR_##name) \ - : "$8","$9","$10","$11","$12","$13","$14","$15","$24"); \ + : "$2","$7","$8","$9","$10","$11","$12","$13","$14","$15", \ + "$24"); \ if (__err == 0) \ return (type) __res; \ errno = __res; \ @@ -1238,14 +267,15 @@ return -1; \ #define _syscall1(type,name,atype,a) \ type name(atype a) \ { \ -register long __res __asm__ ("$2"); \ -register long __err __asm__ ("$7"); \ +long __res, __err; \ __asm__ volatile ("move\t$4,%3\n\t" \ "li\t$2,%2\n\t" \ - "syscall" \ - : "=r" (__res), "=r" (__err) \ - : "i" (__NR_##name),"r" ((long)(a)) \ - : "$4","$8","$9","$10","$11","$12","$13","$14","$15","$24"); \ + "syscall\n\t" \ + "move\t%0, $2\n\t" \ + "move\t%1, $7" \ + : "=r" (__res), "=r" (__err) \ + : "i" (__NR_##name),"r" ((long)(a)) \ + : "$2","$4","$7","$8","$9","$10","$11","$12","$13","$14","$15","$24"); \ if (__err == 0) \ return (type) __res; \ errno = __res; \ @@ -1255,17 +285,18 @@ return -1; \ #define _syscall2(type,name,atype,a,btype,b) \ type name(atype a,btype b) \ { \ -register long __res __asm__ ("$2"); \ -register long __err __asm__ ("$7"); \ +long __res, __err; \ __asm__ volatile ("move\t$4,%3\n\t" \ "move\t$5,%4\n\t" \ "li\t$2,%2\n\t" \ - "syscall" \ + "syscall\n\t" \ + "move\t%0, $2\n\t" \ + "move\t%1, $7" \ : "=r" (__res), "=r" (__err) \ : "i" (__NR_##name),"r" ((long)(a)), \ "r" ((long)(b)) \ - : "$4","$5","$8","$9","$10","$11","$12","$13","$14","$15", \ - "$24"); \ + : "$2","$4","$5","$7","$8","$9","$10","$11","$12","$13", \ + "$14","$15", "$24"); \ if (__err == 0) \ return (type) __res; \ errno = __res; \ @@ -1275,19 +306,20 @@ return -1; \ #define _syscall3(type,name,atype,a,btype,b,ctype,c) \ type name (atype a, btype b, ctype c) \ { \ -register long __res __asm__ ("$2"); \ -register long __err __asm__ ("$7"); \ +long __res, __err; \ __asm__ volatile ("move\t$4,%3\n\t" \ "move\t$5,%4\n\t" \ "move\t$6,%5\n\t" \ "li\t$2,%2\n\t" \ - "syscall" \ + "syscall\n\t" \ + "move\t%0, $2\n\t" \ + "move\t%1, $7" \ : "=r" (__res), "=r" (__err) \ : "i" (__NR_##name),"r" ((long)(a)), \ "r" ((long)(b)), \ "r" ((long)(c)) \ - : "$4","$5","$6","$8","$9","$10","$11","$12","$13","$14", \ - "$15","$24"); \ + : "$2","$4","$5","$6","$7","$8","$9","$10","$11","$12", \ + "$13","$14","$15","$24"); \ if (__err == 0) \ return (type) __res; \ errno = __res; \ @@ -1297,21 +329,22 @@ return -1; \ #define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \ type name (atype a, btype b, ctype c, dtype d) \ { \ -register long __res __asm__ ("$2"); \ -register long __err __asm__ ("$7"); \ +long __res, __err; \ __asm__ volatile ("move\t$4,%3\n\t" \ "move\t$5,%4\n\t" \ "move\t$6,%5\n\t" \ "move\t$7,%6\n\t" \ "li\t$2,%2\n\t" \ - "syscall" \ + "syscall\n\t" \ + "move\t%0, $2\n\t" \ + "move\t%1, $7" \ : "=r" (__res), "=r" (__err) \ : "i" (__NR_##name),"r" ((long)(a)), \ "r" ((long)(b)), \ "r" ((long)(c)), \ "r" ((long)(d)) \ - : "$4","$5","$6","$8","$9","$10","$11","$12","$13","$14", \ - "$15","$24"); \ + : "$2","$4","$5","$6","$7","$8","$9","$10","$11","$12", \ + "$13","$14","$15","$24"); \ if (__err == 0) \ return (type) __res; \ errno = __res; \ @@ -1321,8 +354,7 @@ return -1; \ #define _syscall5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \ type name (atype a,btype b,ctype c,dtype d,etype e) \ { \ -register long __res __asm__ ("$2"); \ -register long __err __asm__ ("$7"); \ +long __res, __err; \ __asm__ volatile ("move\t$4,%3\n\t" \ "move\t$5,%4\n\t" \ "move\t$6,%5\n\t" \ @@ -1331,7 +363,9 @@ __asm__ volatile ("move\t$4,%3\n\t" \ "subu\t$29,24\n\t" \ "sw\t$2,16($29)\n\t" \ "li\t$2,%2\n\t" \ - "syscall\n\t" \ + "syscall\n\t" \ + "move\t%0, $2\n\t" \ + "move\t%1, $7\n\t" \ "addiu\t$29,24" \ : "=r" (__res), "=r" (__err) \ : "i" (__NR_##name),"r" ((long)(a)), \ @@ -1350,8 +384,7 @@ return -1; \ #define _syscall6(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e,ftype,f) \ type name (atype a,btype b,ctype c,dtype d,etype e,ftype f) \ { \ -register long __res __asm__ ("$2"); \ -register long __err __asm__ ("$7"); \ +long __res, __err; \ __asm__ volatile ("move\t$4,%3\n\t" \ "move\t$5,%4\n\t" \ "move\t$6,%5\n\t" \ @@ -1362,7 +395,9 @@ __asm__ volatile ("move\t$4,%3\n\t" \ "sw\t$2,16($29)\n\t" \ "sw\t$3,20($29)\n\t" \ "li\t$2,%2\n\t" \ - "syscall\n\t" \ + "syscall\n\t" \ + "move\t%0, $2\n\t" \ + "move\t%1, $7\n\t" \ "addiu\t$29,24" \ : "=r" (__res), "=r" (__err) \ : "i" (__NR_##name),"r" ((long)(a)), \ @@ -1382,8 +417,7 @@ return -1; \ #define _syscall7(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e,ftype,f,gtype,g) \ type name (atype a,btype b,ctype c,dtype d,etype e,ftype f,gtype g) \ { \ -register long __res __asm__ ("$2"); \ -register long __err __asm__ ("$7"); \ +long __res, __err; \ __asm__ volatile ("move\t$4,%3\n\t" \ "move\t$5,%4\n\t" \ "move\t$6,%5\n\t" \ @@ -1396,7 +430,9 @@ __asm__ volatile ("move\t$4,%3\n\t" \ "sw\t$3,20($29)\n\t" \ "sw\t$2,24($29)\n\t" \ "li\t$2,%2\n\t" \ - "syscall\n\t" \ + "syscall\n\t" \ + "move\t%0, $2\n\t" \ + "move\t%1, $7\n\t" \ "addiu\t$29,32" \ : "=r" (__res), "=r" (__err) \ : "i" (__NR_##name),"r" ((long)(a)), \ @@ -1450,4 +486,4 @@ static inline pid_t wait(int * wait_stat) #endif /* !defined (__KERNEL_SYSCALLS__) */ #endif /* !defined (_LANGUAGE_ASSEMBLY) */ -#endif /* __ASM_MIPS_UNISTD_H */ +#endif /* _ASM_UNISTD_H */ diff --git a/include/asm-mips/watch.h b/include/asm-mips/watch.h index abfc622efee9..7945e0b2fef3 100644 --- a/include/asm-mips/watch.h +++ b/include/asm-mips/watch.h @@ -1,10 +1,9 @@ -/* $Id: watch.h,v 1.3 1998/08/19 21:58:15 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996, 1997, 1998 by Ralf Baechle + * Copyright (C) 1996, 1997, 1998, 2000, 2001 by Ralf Baechle */ #ifndef __ASM_WATCH_H #define __ASM_WATCH_H @@ -35,4 +34,4 @@ extern asmlinkage void __watch_reenable(void); if (watch_available) \ __watch_reenable() -#endif __ASM_WATCH_H +#endif /* __ASM_WATCH_H */ diff --git a/include/asm-mips/wbflush.h b/include/asm-mips/wbflush.h index 31a3679090b1..0d9c9a8683e0 100644 --- a/include/asm-mips/wbflush.h +++ b/include/asm-mips/wbflush.h @@ -27,7 +27,7 @@ extern void (*__wbflush) (void); * we don't need no stinkin' wbflush */ -#define wbflush() +#define wbflush() do { } while(0) #endif diff --git a/include/asm-ppc/bootinfo.h b/include/asm-ppc/bootinfo.h index ce7650611398..2e0841f966f2 100644 --- a/include/asm-ppc/bootinfo.h +++ b/include/asm-ppc/bootinfo.h @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.bootinfo.h 1.7 05/23/01 00:38:42 cort + * BK Id: SCCS/s.bootinfo.h 1.9 06/13/01 15:28:43 paulus */ /* * Non-machine dependent bootinfo structure. Basic idea @@ -34,27 +34,6 @@ struct bi_record { #endif /* CONFIG_APUS */ -/* - * prom_init() is called very early on, before the kernel text - * and data have been mapped to KERNELBASE. At this point the code - * is running at whatever address it has been loaded at, so - * references to extern and static variables must be relocated - * explicitly. The procedure reloc_offset() returns the address - * we're currently running at minus the address we were linked at. - * (Note that strings count as static variables.) - * - * Because OF may have mapped I/O devices into the area starting at - * KERNELBASE, particularly on CHRP machines, we can't safely call - * OF once the kernel has been mapped to KERNELBASE. Therefore all - * OF calls should be done within prom_init(), and prom_init() - * and all routines called within it must be careful to relocate - * references as necessary. - */ -#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset)) -#define PTRUNRELOC(x) ((typeof(x))((unsigned long)(x) - offset)) -#define RELOC(x) (*PTRRELOC(&(x))) #endif /* _PPC_BOOTINFO_H */ #endif /* __KERNEL__ */ - - diff --git a/include/asm-ppc/highmem.h b/include/asm-ppc/highmem.h index 13460cb60575..c7d11722aa20 100644 --- a/include/asm-ppc/highmem.h +++ b/include/asm-ppc/highmem.h @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.highmem.h 1.7 05/17/01 18:14:24 cort + * BK Id: SCCS/s.highmem.h 1.10 06/28/01 15:50:17 paulus */ /* * highmem.h: virtual kernel memory mappings for high memory @@ -94,7 +94,7 @@ static inline void *kmap_atomic(struct page *page, enum km_type type) BUG(); #endif set_pte(kmap_pte+idx, mk_pte(page, kmap_prot)); - flush_hash_page(0, vaddr); + flush_tlb_page(0, vaddr); return (void*) vaddr; } @@ -116,7 +116,7 @@ static inline void kunmap_atomic(void *kvaddr, enum km_type type) * this pte without first remap it */ pte_clear(kmap_pte+idx); - flush_hash_page(0, vaddr); + flush_tlb_page(0, vaddr); #endif } diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h index 422757477089..c3a0a44412d6 100644 --- a/include/asm-ppc/machdep.h +++ b/include/asm-ppc/machdep.h @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.machdep.h 1.11 05/17/01 18:14:25 cort + * BK Id: SCCS/s.machdep.h 1.14 06/28/01 16:13:50 paulus */ #ifdef __KERNEL__ #ifndef _PPC_MACHDEP_H @@ -67,26 +67,19 @@ struct machdep_calls { * optional PCI "hooks" */ - /* Called after scanning the bus, before allocating - * resources - */ + /* Called after scanning the bus, before allocating resources */ void (*pcibios_fixup)(void); - /* Called for each PCI bus in the system - * when it's probed - */ + /* Called for each PCI bus in the system when it's probed */ void (*pcibios_fixup_bus)(struct pci_bus *); - - /* Called when pci_enable_device() is called (initial=0) or - * when a device with no assigned resource is found (initial=1). - * Returns 0 to allow assignement/enabling of the device - */ + + /* Called when pci_enable_device() is called (initial=0) or + * when a device with no assigned resource is found (initial=1). + * Returns 0 to allow assignment/enabling of the device. */ int (*pcibios_enable_device_hook)(struct pci_dev *, int initial); - /* Called at then very end of pcibios_init() - */ + /* Called at then very end of pcibios_init() */ void (*pcibios_after_init)(void); - /* this is for modules, since _machine can be a define -- Cort */ int ppc_machine; diff --git a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h index bdc358194888..d89f9d16c96c 100644 --- a/include/asm-ppc/mmu.h +++ b/include/asm-ppc/mmu.h @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mmu.h 1.7 05/17/01 18:14:25 cort + * BK Id: SCCS/s.mmu.h 1.10 06/28/01 15:50:17 paulus */ /* * PowerPC memory management structures @@ -115,34 +115,6 @@ typedef struct _P601_BAT { P601_BATL batl; /* Lower register */ } P601_BAT; -/* - * Simulated two-level MMU. This structure is used by the kernel - * to keep track of MMU mappings and is used to update/maintain - * the hardware HASH table which is really a cache of mappings. - * - * The simulated structures mimic the hardware available on other - * platforms, notably the 80x86 and 680x0. - */ - -typedef struct _pte { - unsigned long page_num:20; - unsigned long flags:12; /* Page flags (some unused bits) */ -} pte; - -#define PD_SHIFT (10+12) /* Page directory */ -#define PD_MASK 0x02FF -#define PT_SHIFT (12) /* Page Table */ -#define PT_MASK 0x02FF -#define PG_SHIFT (12) /* Page Entry */ - - -/* MMU context */ - -typedef struct _MMU_context { - SEGREG segs[16]; /* Segment registers */ - pte **pmap; /* Two-level page-map structure */ -} MMU_context; - extern void _tlbie(unsigned long va); /* invalidate a TLB entry */ extern void _tlbia(void); /* invalidate all TLB entries */ @@ -167,22 +139,6 @@ extern void _tlbia(void); /* invalidate all TLB entries */ #define BPP_RX 0x01 /* Read only */ #define BPP_RW 0x02 /* Read/write */ -/* Used to set up SDR1 register */ -#define HASH_TABLE_SIZE_64K 0x00010000 -#define HASH_TABLE_SIZE_128K 0x00020000 -#define HASH_TABLE_SIZE_256K 0x00040000 -#define HASH_TABLE_SIZE_512K 0x00080000 -#define HASH_TABLE_SIZE_1M 0x00100000 -#define HASH_TABLE_SIZE_2M 0x00200000 -#define HASH_TABLE_SIZE_4M 0x00400000 -#define HASH_TABLE_MASK_64K 0x000 -#define HASH_TABLE_MASK_128K 0x001 -#define HASH_TABLE_MASK_256K 0x003 -#define HASH_TABLE_MASK_512K 0x007 -#define HASH_TABLE_MASK_1M 0x00F -#define HASH_TABLE_MASK_2M 0x01F -#define HASH_TABLE_MASK_4M 0x03F - /* Control/status registers for the MPC8xx. * A write operation to these registers causes serialized access. * During software tablewalk, the registers used perform mask/shift-add diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h index da57f426538f..ce8f81fd4708 100644 --- a/include/asm-ppc/mmu_context.h +++ b/include/asm-ppc/mmu_context.h @@ -1,18 +1,40 @@ /* - * BK Id: SCCS/s.mmu_context.h 1.9 05/17/01 18:14:25 cort + * BK Id: SCCS/s.mmu_context.h 1.12 06/28/01 15:50:17 paulus */ -#include <linux/config.h> - #ifdef __KERNEL__ #ifndef __PPC_MMU_CONTEXT_H #define __PPC_MMU_CONTEXT_H -/* the way contexts are handled on the ppc they are vsid's and - don't need any special treatment right now. - perhaps I can defer flushing the tlb by keeping a list of - zombie vsid/context's and handling that through destroy_context - later -- Cort +#include <linux/config.h> +#include <asm/atomic.h> +#include <asm/bitops.h> +#include <asm/mmu.h> + +/* + * On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs + * (virtual segment identifiers) for each context. Although the + * hardware supports 24-bit VSIDs, and thus >1 million contexts, + * we only use 32,768 of them. That is ample, since there can be + * at most around 30,000 tasks in the system anyway, and it means + * that we can use a bitmap to indicate which contexts are in use. + * Using a bitmap means that we entirely avoid all of the problems + * that we used to have when the context number overflowed, + * particularly on SMP systems. + * -- paulus. + */ + +/* + * This function defines the mapping from contexts to VSIDs (virtual + * segment IDs). We use a skew on both the context and the high 4 bits + * of the 32-bit virtual address (the "effective segment ID") in order + * to spread out the entries in the MMU hash table. Note, if this + * function is changed then arch/ppc/mm/hashtable.S will have to be + * changed correspondly. + */ +#define CTX_TO_VSID(ctx, va) (((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \ + & 0xffffff) +/* The MPC8xx has only 16 contexts. We rotate through them on each task switch. A better way would be to keep track of tasks that own contexts, and implement an LRU usage. That way very active @@ -32,38 +54,22 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) { } + #ifdef CONFIG_8xx #define NO_CONTEXT 16 #define LAST_CONTEXT 15 -#define BASE_CONTEXT (-1) -#define MUNGE_CONTEXT(n) (n) -#define flush_hash_segments(X, Y) do { } while (0) #elif CONFIG_4xx #define NO_CONTEXT 256 #define LAST_CONTEXT 255 -#define BASE_CONTEXT (0) -#define MUNGE_CONTEXT(n) (n) -#define flush_hash_segments(X, Y) do { } while (0) #else /* PPC 6xx, 7xx CPUs */ -#define NO_CONTEXT 0 -#define BASE_CONTEXT (0) -#define LAST_CONTEXT 0xfffff - -/* - * Allocating context numbers this way tends to spread out - * the entries in the hash table better than a simple linear - * allocation. - */ -#define MUNGE_CONTEXT(n) (((n) * 897) & LAST_CONTEXT) +#define NO_CONTEXT ((mm_context_t) -1) +#define LAST_CONTEXT 32767 #endif -extern atomic_t next_mmu_context; -extern void mmu_context_overflow(void); - /* * Set the current MMU context. * On 32-bit PowerPCs (other than the 8xx embedded chips), this is done by @@ -73,19 +79,58 @@ extern void mmu_context_overflow(void); * and once I implement a real TLB context manager this will disappear. * The PGD is ignored on other processors. - Dan */ -extern void set_context(int context, void *pgd); +extern void set_context(mm_context_t context); /* - * Get a new mmu context for task tsk if necessary. + * Bitmap of contexts in use. + * The size of this bitmap is LAST_CONTEXT + 1 bits. */ -#define get_mmu_context(mm) \ -do { \ - if (mm->context == NO_CONTEXT) { \ - if (atomic_read(&next_mmu_context) == LAST_CONTEXT) \ - mmu_context_overflow(); \ - mm->context = MUNGE_CONTEXT(atomic_inc_return(&next_mmu_context));\ - } \ -} while (0) +extern unsigned long context_map[(LAST_CONTEXT+1) / (8*sizeof(unsigned long))]; + +/* + * This caches the next context number that we expect to be free. + * Its use is an optimization only, we can't rely on this context + * number to be free, but it usually will be. + */ +extern mm_context_t next_mmu_context; + +/* + * If we don't have sufficient contexts to give one to every task + * that could be in the system, we need to be able to steal contexts. + * These variables support that. + */ +#if LAST_CONTEXT < 30000 +#define FEW_CONTEXTS 1 +extern atomic_t nr_free_contexts; +extern struct mm_struct *context_mm[LAST_CONTEXT+1]; +extern void steal_context(void); +#endif + +/* + * Get a new mmu context for the address space described by `mm'. + */ +static inline void get_mmu_context(struct mm_struct *mm) +{ + mm_context_t ctx; + + if (mm->context != NO_CONTEXT) + return; +#ifdef FEW_CONTEXTS + while (atomic_dec_if_positive(&nr_free_contexts) < 0) + steal_context(); +#endif + ctx = next_mmu_context; + while (test_and_set_bit(ctx, context_map)) { + ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx); + if (ctx > LAST_CONTEXT) + ctx = 0; + } + next_mmu_context = (ctx + 1) & LAST_CONTEXT; + mm->context = ctx; +#ifdef FEW_CONTEXTS + context_mm[ctx] = mm; +#endif +} /* * Set up the context for a new address space. @@ -95,14 +140,23 @@ do { \ /* * We're finished using the context for an address space. */ -#define destroy_context(mm) do { } while (0) +static inline void destroy_context(struct mm_struct *mm) +{ + if (mm->context != NO_CONTEXT) { + clear_bit(mm->context, context_map); + mm->context = NO_CONTEXT; +#ifdef FEW_CONTEXTS + atomic_inc(&nr_free_contexts); +#endif + } +} static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, int cpu) { tsk->thread.pgdir = next->pgd; get_mmu_context(next); - set_context(next->context, next->pgd); + set_context(next->context); } /* @@ -113,16 +167,8 @@ static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm { current->thread.pgdir = mm->pgd; get_mmu_context(mm); - set_context(mm->context, mm->pgd); + set_context(mm->context); } -/* - * compute the vsid from the context and segment - * segments > 7 are kernel segments and their - * vsid is the segment -- Cort - */ -#define VSID_FROM_CONTEXT(segment,context) \ - ((segment < 8) ? ((segment) | (context)<<4) : (segment)) - -#endif +#endif /* __PPC_MMU_CONTEXT_H */ #endif /* __KERNEL__ */ diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h index 686ad149d71b..94f898f6da18 100644 --- a/include/asm-ppc/pgtable.h +++ b/include/asm-ppc/pgtable.h @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pgtable.h 1.9 05/17/01 18:14:25 cort + * BK Id: SCCS/s.pgtable.h 1.12 06/28/01 15:50:17 paulus */ #ifdef __KERNEL__ #ifndef _PPC_PGTABLE_H @@ -20,8 +20,8 @@ extern void local_flush_tlb_mm(struct mm_struct *mm); extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); extern void local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end); -static inline void flush_hash_page(unsigned context, unsigned long va) - { } +#define update_mmu_cache(vma, addr, pte) do { } while (0) + #elif defined(CONFIG_8xx) #define __tlbia() asm volatile ("tlbia" : : ) @@ -35,9 +35,9 @@ static inline void local_flush_tlb_page(struct vm_area_struct *vma, static inline void local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { __tlbia(); } -static inline void flush_hash_page(unsigned context, unsigned long va) - { } -#else +#define update_mmu_cache(vma, addr, pte) do { } while (0) + +#else /* 6xx, 7xx, 7xxx cpus */ struct mm_struct; struct vm_area_struct; extern void local_flush_tlb_all(void); @@ -45,6 +45,15 @@ extern void local_flush_tlb_mm(struct mm_struct *mm); extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); extern void local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end); + +/* + * This gets called at the end of handling a page fault, when + * the kernel has put a new PTE into the page table for the process. + * We use it to put a corresponding HPTE into the hash table + * ahead of time, instead of waiting for the inevitable extra + * hash-table miss exception. + */ +extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t); #endif #define flush_tlb_all local_flush_tlb_all @@ -52,16 +61,20 @@ extern void local_flush_tlb_range(struct mm_struct *mm, unsigned long start, #define flush_tlb_page local_flush_tlb_page #define flush_tlb_range local_flush_tlb_range +/* + * This is called in munmap when we have freed up some page-table + * pages. We don't need to do anything here, there's nothing special + * about our page-table pages. -- paulus + */ static inline void flush_tlb_pgtables(struct mm_struct *mm, - unsigned long start, unsigned long end) + unsigned long start, unsigned long end) { - /* PPC has hw page tables. */ } /* * No cache flushing is required when address mappings are * changed, because the caches on PowerPCs are physically - * addressed. + * addressed. -- paulus * Also, when SMP we use the coherency (M) bit of the * BATs and PTEs. -- Cort */ @@ -88,12 +101,12 @@ extern unsigned long ioremap_bot, ioremap_base; * the virtual to physical address mapping. * * We use the hash table as an extended TLB, i.e. a cache of currently - * active mappings. We maintain a two-level page table tree, much like - * that used by the i386, for the sake of the Linux memory management code. - * Low-level assembler code in head.S (procedure hash_page) is responsible - * for extracting ptes from the tree and putting them into the hash table - * when necessary, and updating the accessed and modified bits in the - * page table tree. + * active mappings. We maintain a two-level page table tree, much + * like that used by the i386, for the sake of the Linux memory + * management code. Low-level assembler code in hashtable.S + * (procedure hash_page) is responsible for extracting ptes from the + * tree and putting them into the hash table when necessary, and + * updating the accessed and modified bits in the page table tree. */ /* @@ -189,12 +202,11 @@ extern unsigned long ioremap_bot, ioremap_base; #define _PAGE_NO_CACHE 0x004 /* I: caching is inhibited */ #define _PAGE_WRITETHRU 0x008 /* W: caching is write-through */ #define _PAGE_USER 0x010 /* matches one of the zone permission bits */ +#define _PAGE_EXEC 0x020 /* software: i-cache coherency required */ #define _PAGE_PRESENT 0x040 /* software: PTE contains a translation */ #define _PAGE_DIRTY 0x100 /* C: page changed */ #define _PAGE_RW 0x200 /* Writes permitted */ #define _PAGE_ACCESSED 0x400 /* R: page referenced */ -#define _PAGE_HWWRITE 0x800 /* software: _PAGE_RW & _PAGE_DIRTY */ -#define _PAGE_SHARED 0 #elif defined(CONFIG_8xx) /* Definitions for 8xx embedded chips. */ @@ -205,48 +217,62 @@ extern unsigned long ioremap_bot, ioremap_base; /* These five software bits must be masked out when the entry is loaded * into the TLB. */ -#define _PAGE_DIRTY 0x0008 /* software: page changed */ +#define _PAGE_EXEC 0x0008 /* software: i-cache coherency required */ #define _PAGE_GUARDED 0x0010 /* software: guarded access */ #define _PAGE_WRITETHRU 0x0020 /* software: use writethrough cache */ #define _PAGE_RW 0x0040 /* software: user write access allowed */ #define _PAGE_ACCESSED 0x0080 /* software: page referenced */ -#define _PAGE_HWWRITE 0x0100 /* C: page changed (write protect) */ -#define _PAGE_USER 0x0800 /* One of the PP bits, the other must be 0 */ +#define _PAGE_DIRTY 0x0100 /* C: page changed (write protect) */ +#define _PAGE_USER 0x0800 /* One of the PP bits, the other is USER&~RW */ #else /* CONFIG_6xx */ /* Definitions for 60x, 740/750, etc. */ #define _PAGE_PRESENT 0x001 /* software: pte contains a translation */ -#define _PAGE_USER 0x002 /* matches one of the PP bits */ -#define _PAGE_RW 0x004 /* software: user write access allowed */ -#define _PAGE_GUARDED 0x008 +#define _PAGE_HASHPTE 0x002 /* hash_page has made an HPTE for this pte */ +#define _PAGE_USER 0x004 /* usermode access allowed */ +#define _PAGE_GUARDED 0x008 /* G: prohibit speculative access */ #define _PAGE_COHERENT 0x010 /* M: enforce memory coherence (SMP systems) */ #define _PAGE_NO_CACHE 0x020 /* I: cache inhibit */ #define _PAGE_WRITETHRU 0x040 /* W: cache write-through */ #define _PAGE_DIRTY 0x080 /* C: page changed */ #define _PAGE_ACCESSED 0x100 /* R: page referenced */ -#define _PAGE_HWWRITE 0x200 /* software: _PAGE_RW & _PAGE_DIRTY */ +#define _PAGE_EXEC 0x200 /* software: i-cache coherency required */ +#define _PAGE_RW 0x400 /* software: user write access allowed */ +#endif + +#ifndef _PAGE_HASHPTE +#define _PAGE_HASHPTE 0 +#endif +#ifndef _PAGE_SHARED #define _PAGE_SHARED 0 #endif #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) -#ifdef CONFIG_SMP -#define _PAGE_BASE _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT -#else +/* + * Note: the _PAGE_COHERENT bit automatically gets set in the hardware + * PTE if CONFIG_SMP is defined (hash_page does this); there is no need + * to have it in the Linux PTE, and in fact the bit could be reused for + * another purpose. -- paulus. + */ #define _PAGE_BASE _PAGE_PRESENT | _PAGE_ACCESSED -#endif -#define _PAGE_WRENABLE _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE +#define _PAGE_WRENABLE _PAGE_RW | _PAGE_DIRTY -#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) +#define _PAGE_KERNEL _PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED +#define _PAGE_IO _PAGE_KERNEL | _PAGE_NO_CACHE | _PAGE_GUARDED -#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER | \ - _PAGE_SHARED) -#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_NONE __pgprot(_PAGE_BASE) #define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER) -#define PAGE_KERNEL __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED) -#define PAGE_KERNEL_CI __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED | \ - _PAGE_NO_CACHE ) +#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) +#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW) +#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC) +#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) + +#define PAGE_KERNEL __pgprot(_PAGE_KERNEL) +#define PAGE_KERNEL_RO __pgprot(_PAGE_BASE | _PAGE_SHARED) +#define PAGE_KERNEL_CI __pgprot(_PAGE_IO) /* * The PowerPC can only do execute protection on a segment (256MB) basis, @@ -255,22 +281,22 @@ extern unsigned long ioremap_bot, ioremap_base; * This is the closest we can get.. */ #define __P000 PAGE_NONE -#define __P001 PAGE_READONLY +#define __P001 PAGE_READONLY_X #define __P010 PAGE_COPY -#define __P011 PAGE_COPY +#define __P011 PAGE_COPY_X #define __P100 PAGE_READONLY -#define __P101 PAGE_READONLY +#define __P101 PAGE_READONLY_X #define __P110 PAGE_COPY -#define __P111 PAGE_COPY +#define __P111 PAGE_COPY_X #define __S000 PAGE_NONE -#define __S001 PAGE_READONLY +#define __S001 PAGE_READONLY_X #define __S010 PAGE_SHARED -#define __S011 PAGE_SHARED +#define __S011 PAGE_SHARED_X #define __S100 PAGE_READONLY -#define __S101 PAGE_READONLY +#define __S101 PAGE_READONLY_X #define __S110 PAGE_SHARED -#define __S111 PAGE_SHARED +#define __S111 PAGE_SHARED_X #ifndef __ASSEMBLY__ /* @@ -280,33 +306,11 @@ extern unsigned long ioremap_bot, ioremap_base; extern unsigned long empty_zero_page[1024]; #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) -/* - * BAD_PAGETABLE is used when we need a bogus page-table, while - * BAD_PAGE is used for a bogus page. - * - * ZERO_PAGE is a global shared page that is always zero: used - * for zero-mapped memory areas etc.. - */ -extern pte_t __bad_page(void); -extern pte_t * __bad_pagetable(void); - -#define BAD_PAGETABLE __bad_pagetable() -#define BAD_PAGE __bad_page() #endif /* __ASSEMBLY__ */ -/* number of bits that fit into a memory pointer */ -#define BITS_PER_PTR (8*sizeof(unsigned long)) - -/* to align the pointer to a pointer address */ -#define PTR_MASK (~(sizeof(void*)-1)) - -/* sizeof(void*) == 1<<SIZEOF_PTR_LOG2 */ -/* 64-bit machines, beware! SRB. */ -#define SIZEOF_PTR_LOG2 2 - -#define pte_none(pte) (!pte_val(pte)) +#define pte_none(pte) ((pte_val(pte) & ~_PAGE_HASHPTE) == 0) #define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT) -#define pte_clear(ptep) do { pte_val(*(ptep)) = 0; } while (0) +#define pte_clear(ptep) do { set_pte((ptep), __pte(0)); } while (0) #define pmd_none(pmd) (!pmd_val(pmd)) #define pmd_bad(pmd) ((pmd_val(pmd) & ~PAGE_MASK) != 0) @@ -316,8 +320,7 @@ extern pte_t * __bad_pagetable(void); /* * Permanent address of a page. */ -#define page_address(page) ((page)->virtual) -#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) +#define page_address(page) ((page)->virtual) #define pte_page(x) (mem_map+(unsigned long)((pte_val(x) >> PAGE_SHIFT))) #ifndef __ASSEMBLY__ @@ -340,7 +343,7 @@ static inline int pgd_present(pgd_t pgd) { return 1; } */ static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; } static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; } -static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_USER; } +static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC; } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } @@ -349,42 +352,26 @@ static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACH static inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_USER; return pte; } -static inline pte_t pte_exprotect(pte_t pte) { - pte_val(pte) &= ~_PAGE_USER; return pte; } static inline pte_t pte_wrprotect(pte_t pte) { - pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; } + pte_val(pte) &= ~_PAGE_RW; return pte; } +static inline pte_t pte_exprotect(pte_t pte) { + pte_val(pte) &= ~_PAGE_EXEC; return pte; } static inline pte_t pte_mkclean(pte_t pte) { - pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; } + pte_val(pte) &= ~_PAGE_DIRTY; return pte; } static inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; } static inline pte_t pte_mkread(pte_t pte) { pte_val(pte) |= _PAGE_USER; return pte; } static inline pte_t pte_mkexec(pte_t pte) { - pte_val(pte) |= _PAGE_USER; return pte; } -static inline pte_t pte_mkwrite(pte_t pte) -{ - pte_val(pte) |= _PAGE_RW; - if (pte_val(pte) & _PAGE_DIRTY) - pte_val(pte) |= _PAGE_HWWRITE; - return pte; -} -static inline pte_t pte_mkdirty(pte_t pte) -{ - pte_val(pte) |= _PAGE_DIRTY; - if (pte_val(pte) & _PAGE_RW) - pte_val(pte) |= _PAGE_HWWRITE; - return pte; -} + pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; } +static inline pte_t pte_mkwrite(pte_t pte) { + pte_val(pte) |= _PAGE_RW; return pte; } +static inline pte_t pte_mkdirty(pte_t pte) { + pte_val(pte) |= _PAGE_DIRTY; return pte; } static inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; } -/* Certain architectures need to do special things when pte's - * within a page table are directly modified. Thus, the following - * hook is made available. - */ -#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval)) - /* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. @@ -421,11 +408,11 @@ static inline unsigned long pte_update(pte_t *p, unsigned long clr, { unsigned long old, tmp; - __asm__ __volatile__("\n\ -1: lwarx %0,0,%3 \n\ - andc %1,%0,%4 \n\ - or %1,%1,%5 \n\ - stwcx. %1,0,%3 \n\ + __asm__ __volatile__("\ +1: lwarx %0,0,%3\n\ + andc %1,%0,%4\n\ + or %1,%1,%5\n\ + stwcx. %1,0,%3\n\ bne- 1b" : "=&r" (old), "=&r" (tmp), "=m" (*p) : "r" (p), "r" (clr), "r" (set), "m" (*p) @@ -433,6 +420,12 @@ static inline unsigned long pte_update(pte_t *p, unsigned long clr, return old; } +/* + * Writing a new value into the PTE doesn't disturb the state of the + * _PAGE_HASHPTE bit, on those machines which use an MMU hash table. + */ +extern void set_pte(pte_t *ptep, pte_t pte); + static inline int ptep_test_and_clear_young(pte_t *ptep) { return (pte_update(ptep, _PAGE_ACCESSED, 0) & _PAGE_ACCESSED) != 0; @@ -440,36 +433,25 @@ static inline int ptep_test_and_clear_young(pte_t *ptep) static inline int ptep_test_and_clear_dirty(pte_t *ptep) { - return (pte_update(ptep, _PAGE_DIRTY | _PAGE_HWWRITE, 0) - & _PAGE_DIRTY) != 0; + return (pte_update(ptep, _PAGE_DIRTY, 0) & _PAGE_DIRTY) != 0; } static inline pte_t ptep_get_and_clear(pte_t *ptep) { - return __pte(pte_update(ptep, ~0UL, 0)); + return __pte(pte_update(ptep, ~_PAGE_HASHPTE, 0)); } static inline void ptep_set_wrprotect(pte_t *ptep) { - pte_update(ptep, _PAGE_RW | _PAGE_HWWRITE, 0); + pte_update(ptep, _PAGE_RW, 0); } static inline void ptep_mkdirty(pte_t *ptep) { - /* - * N.B. this doesn't set the _PAGE_HWWRITE bit in the case - * where _PAGE_RW is set and _PAGE_DIRTY was clear. This - * doesn't matter; all it will mean is that if the next call - * to hash_page for this page is for a read, it will put a - * readonly HPTE into the hash table rather than a R/W HPTE. - * A call to hash_page for a write to this page will set - * _PAGE_HWWRITE and put a R/W HPTE into the hash table. - * -- paulus. - */ pte_update(ptep, 0, _PAGE_DIRTY); } -#define pte_same(A,B) (pte_val(A) == pte_val(B)) +#define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0) #define pmd_page(pmd) (pmd_val(pmd)) @@ -496,25 +478,25 @@ extern pgd_t swapper_pg_dir[1024]; extern void paging_init(void); /* - * Page tables may have changed. We don't need to do anything here - * as entries are faulted into the hash table by the low-level - * data/instruction access exception handlers. + * When flushing the tlb entry for a page, we also need to flush the hash + * table entry. flush_hash_page is assembler (for speed) in hashtable.S. */ -#define update_mmu_cache(vma, addr, pte) do { } while (0) +extern int flush_hash_page(unsigned context, unsigned long va, pte_t *ptep); + +/* Add an HPTE to the hash table */ +extern void add_hash_page(unsigned context, unsigned long va, pte_t *ptep); /* - * When flushing the tlb entry for a page, we also need to flush the - * hash table entry. flush_hash_page is assembler (for speed) in head.S. + * Encode and decode a swap entry. + * Note that the bits we use in a PTE for representing a swap entry + * must not include the _PAGE_PRESENT bit, or the _PAGE_HASHPTE bit + * (if used). -- paulus */ -extern void flush_hash_segments(unsigned low_vsid, unsigned high_vsid); -extern void flush_hash_page(unsigned context, unsigned long va); - -/* Encode and de-code a swap entry */ -#define SWP_TYPE(entry) (((entry).val >> 1) & 0x3f) -#define SWP_OFFSET(entry) ((entry).val >> 8) -#define SWP_ENTRY(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) }) -#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -#define swp_entry_to_pte(x) ((pte_t) { (x).val }) +#define SWP_TYPE(entry) ((entry).val & 0x3f) +#define SWP_OFFSET(entry) ((entry).val >> 6) +#define SWP_ENTRY(type, offset) ((swp_entry_t) { (type) | ((offset) << 6) }) +#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) >> 2 }) +#define swp_entry_to_pte(x) ((pte_t) { (x).val << 2 }) /* CONFIG_APUS */ /* For virtual address to physical address conversion */ @@ -545,7 +527,6 @@ extern void kernel_set_cachemode (unsigned long address, unsigned long size, unsigned int cmode); /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ -#define PageSkip(page) (0) #define kern_addr_valid(addr) (1) #define io_remap_page_range remap_page_range diff --git a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h index 3bd0b2a7e345..4c18e818c3a3 100644 --- a/include/asm-ppc/processor.h +++ b/include/asm-ppc/processor.h @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.processor.h 1.19 05/18/01 08:18:10 patch + * BK Id: SCCS/s.processor.h 1.24 06/15/01 13:56:56 paulus */ #ifdef __KERNEL__ #ifndef __ASM_PPC_PROCESSOR_H @@ -445,6 +445,7 @@ #define PVR_403GC 0x00200200 #define PVR_403GCX 0x00201400 #define PVR_405GP 0x40110000 +#define PVR_STB03XXX 0x40310000 #define PVR_601 0x00010000 #define PVR_602 0x00050000 #define PVR_603 0x00030000 @@ -459,6 +460,8 @@ #define PVR_750 PVR_740 #define PVR_740P 0x10080000 #define PVR_750P PVR_740P +#define PVR_7400 0x000C0000 +#define PVR_7410 0x800C0000 /* * For the 8xx processors, all of them report the same PVR family for * the PowerPC core. The various versions of these processors must be @@ -469,7 +472,6 @@ #define PVR_823 PVR_821 #define PVR_850 PVR_821 #define PVR_860 PVR_821 -#define PVR_7400 0x000C0000 #define PVR_8240 0x00810100 #define PVR_8260 PVR_8240 diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h index 11f57aadb4d7..43e3f600341a 100644 --- a/include/asm-ppc/prom.h +++ b/include/asm-ppc/prom.h @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.prom.h 1.11 05/18/01 08:18:10 patch + * BK Id: SCCS/s.prom.h 1.14 06/13/01 15:28:43 paulus */ /* * Definitions for talking to the Open Firmware PROM on @@ -45,6 +45,9 @@ struct property { struct property *next; }; +/* + * Note: don't change this structure for now or you'll break BootX ! + */ struct device_node { char *name; char *type; @@ -60,10 +63,6 @@ struct device_node { struct device_node *sibling; struct device_node *next; /* next device of same type */ struct device_node *allnext; /* next in list of all nodes */ -#if 0 /* Don't change this structure for now or you'll break BootX ! */ - int n_addr_cells; - int n_size_cells; -#endif }; struct prom_args; @@ -102,5 +101,23 @@ extern void map_bootx_text(void); extern void bootx_update_display(unsigned long phys, int width, int height, int depth, int pitch); +/* + * When we call back to the Open Firmware client interface, we usually + * have to do that before the kernel is relocated to its final location + * (this is because we can't use OF after we have overwritten the + * exception vectors with our exception handlers). These macros assist + * in performing the address calculations that we need to do to access + * data when the kernel is running at an address that is different from + * the address that the kernel is linked at. The reloc_offset() function + * returns the difference between these two addresses and the macros + * simplify the process of adding or subtracting this offset to/from + * pointer values. See arch/ppc/kernel/prom.c for how these are used. + */ +extern unsigned long reloc_offset(void); + +#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset)) +#define PTRUNRELOC(x) ((typeof(x))((unsigned long)(x) - offset)) +#define RELOC(x) (*PTRRELOC(&(x))) + #endif /* _PPC_PROM_H */ #endif /* __KERNEL__ */ diff --git a/include/asm-ppc/time.h b/include/asm-ppc/time.h index 2c9f1026882e..2a774bc50428 100644 --- a/include/asm-ppc/time.h +++ b/include/asm-ppc/time.h @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.time.h 1.10 05/17/01 18:14:26 cort + * BK Id: SCCS/s.time.h 1.13 06/27/01 14:49:58 trini */ /* * Common time prototypes and such for all ppc machines. @@ -24,6 +24,8 @@ extern unsigned long disarm_decr[NR_CPUS]; extern void to_tm(int tim, struct rtc_time * tm); extern time_t last_rtc_update; +extern void set_dec_cpu6(unsigned int val); + int via_calibrate_decr(void); /* Accessor functions for the decrementer register. diff --git a/include/asm-sh/hitachi_se.h b/include/asm-sh/hitachi_se.h index 05b701e1f1c6..8aafb71a47e1 100644 --- a/include/asm-sh/hitachi_se.h +++ b/include/asm-sh/hitachi_se.h @@ -38,7 +38,7 @@ #define PA_LED 0xb0c00000 /* LED */ #define PA_BCR 0xb1400000 /* FPGA */ -#define PA_MRSHPC 0xb83fffe0 /* MR-SHPC-01 PCMCIA controler */ +#define PA_MRSHPC 0xb83fffe0 /* MR-SHPC-01 PCMCIA controller */ #define PA_MRSHPC_MW1 0xb8400000 /* MR-SHPC-01 memory window base */ #define PA_MRSHPC_MW2 0xb8500000 /* MR-SHPC-01 attribute window base */ #define PA_MRSHPC_IO 0xb8600000 /* MR-SHPC-01 I/O window base */ diff --git a/include/asm-sparc/hardirq.h b/include/asm-sparc/hardirq.h index ac828721c7e0..ab7958844f44 100644 --- a/include/asm-sparc/hardirq.h +++ b/include/asm-sparc/hardirq.h @@ -1,7 +1,7 @@ /* hardirq.h: 32-bit Sparc hard IRQ support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1998-2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 1998-2000 Anton Blanchard (anton@samba.org) */ #ifndef __SPARC_HARDIRQ_H diff --git a/include/asm-sparc/vaddrs.h b/include/asm-sparc/vaddrs.h index 704f79003d9f..e2f6fbe91fc8 100644 --- a/include/asm-sparc/vaddrs.h +++ b/include/asm-sparc/vaddrs.h @@ -9,7 +9,7 @@ * which important things will be mapped. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 2000 Anton Blanchard (anton@samba.org) */ #define SRMMU_MAXMEM 0x0c000000 diff --git a/include/asm-sparc64/starfire.h b/include/asm-sparc64/starfire.h index d59bda0c3a9d..a738fb363a40 100644 --- a/include/asm-sparc64/starfire.h +++ b/include/asm-sparc64/starfire.h @@ -1,7 +1,7 @@ /* $Id: starfire.h,v 1.1 2000/09/21 06:18:53 anton Exp $ * starfire.h: Group all starfire specific code together. * - * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 2000 Anton Blanchard (anton@samba.org) */ #ifndef _SPARC64_STARFIRE_H diff --git a/include/linux/agp_backend.h b/include/linux/agp_backend.h index 221be1c68bca..63619c2eb6f6 100644 --- a/include/linux/agp_backend.h +++ b/include/linux/agp_backend.h @@ -45,7 +45,7 @@ enum chipset_type { INTEL_BX, INTEL_GX, INTEL_I810, - INTEL_I815, + INTEL_I815, INTEL_I840, INTEL_I850, VIA_GENERIC, @@ -65,7 +65,10 @@ enum chipset_type { ALI_M1641, ALI_M1647, ALI_M1651, - ALI_GENERIC + ALI_GENERIC, + SVWRKS_HE, + SVWRKS_LE, + SVWRKS_GENERIC }; typedef struct _agp_version { diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h index ef8931cd7b5f..2b14cb90f604 100644 --- a/include/linux/atmdev.h +++ b/include/linux/atmdev.h @@ -22,6 +22,13 @@ max cell rate: 353207.547 cells/sec */ #define ATM_25_PCR ((25600000/8-8000)/54) /* 25 Mbps ATM cell rate (59111) */ +#define ATM_OC12_PCR (622080000/1080*1040/8/53) + /* OC12 link rate: 622080000 bps + SONET overhead: /1080*1040 + bits per cell: /8/53 + max cell rate: 1412830.188 cells/sec */ +#define ATM_DS3_PCR (8000*12) + /* DS3: 12 cells in a 125 usec time slot */ #define ATM_PDU_OVHD 0 /* number of bytes to charge against buffer quota per PDU */ diff --git a/include/linux/isdn.h b/include/linux/isdn.h index bb57005b1e07..18772903d770 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.111.6.6 2001/05/17 21:15:34 kai Exp $ +/* $Id: isdn.h,v 1.111.6.7 2001/06/30 19:47:51 kai Exp $ * Main header for the Linux ISDN subsystem (linklevel). * @@ -27,6 +27,15 @@ #include <linux/ioctl.h> +#ifdef CONFIG_COBALT_MICRO_SERVER +/* Save memory */ +#define ISDN_MAX_DRIVERS 2 +#define ISDN_MAX_CHANNELS 8 +#else +#define ISDN_MAX_DRIVERS 32 +#define ISDN_MAX_CHANNELS 64 +#endif + /* New ioctl-codes */ #define IIOCNETAIF _IO('I',1) #define IIOCNETDIF _IO('I',2) @@ -181,14 +190,6 @@ typedef struct { * the correspondent code in isdn.c */ -#ifdef CONFIG_COBALT_MICRO_SERVER -/* Save memory */ -#define ISDN_MAX_DRIVERS 2 -#define ISDN_MAX_CHANNELS 8 -#else -#define ISDN_MAX_DRIVERS 32 -#define ISDN_MAX_CHANNELS 64 -#endif #define ISDN_MINOR_B 0 #define ISDN_MINOR_BMAX (ISDN_MAX_CHANNELS-1) #define ISDN_MINOR_CTRL 64 diff --git a/include/linux/isdn/tpam.h b/include/linux/isdn/tpam.h new file mode 100644 index 000000000000..9f65bea49d11 --- /dev/null +++ b/include/linux/isdn/tpam.h @@ -0,0 +1,56 @@ +/* $Id: tpam.h,v 1.1.2.1 2001/06/08 08:23:46 kai Exp $ + * + * Turbo PAM ISDN driver for Linux. (Kernel Driver) + * + * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * For all support questions please contact: <support@auvertech.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _TPAM_H_ +#define _TPAM_H_ + +#include <linux/types.h> +#include <linux/pci.h> + +/* IOCTL commands */ +#define TPAM_CMD_DSPLOAD 0x0001 +#define TPAM_CMD_DSPSAVE 0x0002 +#define TPAM_CMD_DSPRUN 0x0003 +#define TPAM_CMD_LOOPMODEON 0x0004 +#define TPAM_CMD_LOOPMODEOFF 0x0005 + +/* addresses of debug information zones on board */ +#define TPAM_TRAPAUDIT_REGISTER 0x005493e4 +#define TPAM_NCOAUDIT_REGISTER 0x00500000 +#define TPAM_MSGAUDIT_REGISTER 0x008E30F0 + +/* length of debug information zones on board */ +#define TPAM_TRAPAUDIT_LENGTH 10000 +#define TPAM_NCOAUDIT_LENGTH 300000 +#define TPAM_NCOAUDIT_COUNT 30 +#define TPAM_MSGAUDIT_LENGTH 60000 + +/* IOCTL load/save parameter */ +typedef struct tpam_dsp_ioctl { + __u32 address; /* address to load/save data */ + __u32 data_len; /* size of data to be loaded/saved */ + __u8 data[0]; /* data */ +} tpam_dsp_ioctl; + +#endif /* _TPAM_H_ */ diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h index f6239bd176d9..cca81b6b50a5 100644 --- a/include/linux/isdnif.h +++ b/include/linux/isdnif.h @@ -1,4 +1,4 @@ -/* $Id: isdnif.h,v 1.37.6.2 2001/05/17 21:15:34 kai Exp $ +/* $Id: isdnif.h,v 1.37.6.4 2001/06/09 15:14:19 kai Exp $ * Linux ISDN subsystem * @@ -433,6 +433,7 @@ typedef struct { #ifdef CONFIG_ISDN_TTY_FAX T30_s *fax; /* Pointer to ttys fax struct */ #endif + ulong userdata; /* User Data */ } parm; } isdn_ctrl; diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index f183f57a5e87..ed5fbc59d247 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -81,7 +81,7 @@ void nfsd_racache_shutdown(void); int nfsd_lookup(struct svc_rqst *, struct svc_fh *, const char *, int, struct svc_fh *); int nfsd_setattr(struct svc_rqst *, struct svc_fh *, - struct iattr *); + struct iattr *, int, time_t); int nfsd_create(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, int type, dev_t rdev, struct svc_fh *res); @@ -143,6 +143,7 @@ void nfsd_lockd_unexport(struct svc_client *); #define nfserr_noent __constant_htonl(NFSERR_NOENT) #define nfserr_io __constant_htonl(NFSERR_IO) #define nfserr_nxio __constant_htonl(NFSERR_NXIO) +#define nfserr_eagain __constant_htonl(NFSERR_EAGAIN) #define nfserr_acces __constant_htonl(NFSERR_ACCES) #define nfserr_exist __constant_htonl(NFSERR_EXIST) #define nfserr_xdev __constant_htonl(NFSERR_XDEV) @@ -160,9 +161,10 @@ void nfsd_lockd_unexport(struct svc_client *); #define nfserr_dquot __constant_htonl(NFSERR_DQUOT) #define nfserr_stale __constant_htonl(NFSERR_STALE) #define nfserr_remote __constant_htonl(NFSERR_REMOTE) +#define nfserr_wflush __constant_htonl(NFSERR_WFLUSH) #define nfserr_badhandle __constant_htonl(NFSERR_BADHANDLE) -#define nfserr_notsync __constant_htonl(NFSERR_NOTSYNC) -#define nfserr_badcookie __constant_htonl(NFSERR_BADCOOKIE) +#define nfserr_notsync __constant_htonl(NFSERR_NOT_SYNC) +#define nfserr_badcookie __constant_htonl(NFSERR_BAD_COOKIE) #define nfserr_notsupp __constant_htonl(NFSERR_NOTSUPP) #define nfserr_toosmall __constant_htonl(NFSERR_TOOSMALL) #define nfserr_serverfault __constant_htonl(NFSERR_SERVERFAULT) diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index dc2dae68d1c7..2149cff1db25 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -199,7 +199,7 @@ inline static char * SVCFH_fmt(struct svc_fh *fhp) * Function prototypes */ u32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int); -int fh_compose(struct svc_fh *, struct svc_export *, struct dentry *); +int fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *); int fh_update(struct svc_fh *); void fh_put(struct svc_fh *); diff --git a/include/linux/pci.h b/include/linux/pci.h index 3b4ae41a9f14..9fc5ccf43a5a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -641,6 +641,8 @@ static inline void pci_set_master(struct pci_dev *dev) { } static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } static inline void pci_disable_device(struct pci_dev *dev) { } static inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; } +static inline int pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask) { return -EIO; } +static inline int pci_set_power_state(struct pci_dev *dev, int state) { return 0; } static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;} static inline int pci_register_driver(struct pci_driver *drv) { return 0;} static inline void pci_unregister_driver(struct pci_driver *drv) { } diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index bb42ad226df2..9575ef38dee0 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -211,6 +211,7 @@ #define PCI_DEVICE_ID_ATI_RAGE128_PP 0x5050 #define PCI_DEVICE_ID_ATI_RAGE128_PQ 0x5051 #define PCI_DEVICE_ID_ATI_RAGE128_PR 0x5052 +#define PCI_DEVICE_ID_ATI_RAGE128_TR 0x5452 #define PCI_DEVICE_ID_ATI_RAGE128_PS 0x5053 #define PCI_DEVICE_ID_ATI_RAGE128_PT 0x5054 #define PCI_DEVICE_ID_ATI_RAGE128_PU 0x5055 @@ -326,6 +327,7 @@ #define PCI_DEVICE_ID_IBM_TR_WAKE 0x003e #define PCI_DEVICE_ID_IBM_MPIC 0x0046 #define PCI_DEVICE_ID_IBM_3780IDSP 0x007d +#define PCI_DEVICE_ID_IBM_CHUKAR 0x0096 #define PCI_DEVICE_ID_IBM_405GP 0x0156 #define PCI_DEVICE_ID_IBM_MPIC_2 0xffff @@ -345,6 +347,9 @@ #define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001 #define PCI_DEVICE_ID_AMD_SCSI 0x2020 #define PCI_DEVICE_ID_AMD_FE_GATE_7006 0x7006 +#define PCI_DEVICE_ID_AMD_FE_GATE_7007 0x7007 +#define PCI_DEVICE_ID_AMD_FE_GATE_700E 0x700E +#define PCI_DEVICE_ID_AMD_FE_GATE_700F 0x700F #define PCI_DEVICE_ID_AMD_COBRA_7400 0x7400 #define PCI_DEVICE_ID_AMD_COBRA_7401 0x7401 #define PCI_DEVICE_ID_AMD_COBRA_7403 0x7403 @@ -353,6 +358,10 @@ #define PCI_DEVICE_ID_AMD_VIPER_7409 0x7409 #define PCI_DEVICE_ID_AMD_VIPER_740B 0x740B #define PCI_DEVICE_ID_AMD_VIPER_740C 0x740C +#define PCI_DEVICE_ID_AMD_VIPER_7410 0x7410 +#define PCI_DEVICE_ID_AMD_VIPER_7411 0x7411 +#define PCI_DEVICE_ID_AMD_VIPER_7413 0x7413 +#define PCI_DEVICE_ID_AMD_VIPER_7414 0x7414 #define PCI_VENDOR_ID_TRIDENT 0x1023 #define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000 @@ -403,6 +412,7 @@ #define PCI_VENDOR_ID_NEC 0x1033 #define PCI_DEVICE_ID_NEC_PCX2 0x0046 #define PCI_DEVICE_ID_NEC_NILE4 0x005a +#define PCI_DEVICE_ID_NEC_VRC5476 0x009b #define PCI_VENDOR_ID_FD 0x1036 #define PCI_DEVICE_ID_FD_36C70 0x0000 @@ -417,15 +427,20 @@ #define PCI_DEVICE_ID_SI_501 0x0406 #define PCI_DEVICE_ID_SI_496 0x0496 #define PCI_DEVICE_ID_SI_300 0x0300 +#define PCI_DEVICE_ID_SI_315H 0x0310 +#define PCI_DEVICE_ID_SI_315 0x0315 #define PCI_DEVICE_ID_SI_530 0x0530 #define PCI_DEVICE_ID_SI_540 0x0540 +#define PCI_DEVICE_ID_SI_550 0x0550 #define PCI_DEVICE_ID_SI_540_VGA 0x5300 +#define PCI_DEVICE_ID_SI_550_VGA 0x5315 #define PCI_DEVICE_ID_SI_601 0x0601 #define PCI_DEVICE_ID_SI_620 0x0620 #define PCI_DEVICE_ID_SI_630 0x0630 -#define PCI_DEVICE_ID_SI_730 0x0730 +#define PCI_DEVICE_ID_SI_730 0x0730 #define PCI_DEVICE_ID_SI_630_VGA 0x6300 #define PCI_DEVICE_ID_SI_730_VGA 0x7300 +#define PCI_DEVICE_ID_SI_900 0x0900 #define PCI_DEVICE_ID_SI_5107 0x5107 #define PCI_DEVICE_ID_SI_5300 0x5300 #define PCI_DEVICE_ID_SI_5511 0x5511 @@ -439,6 +454,7 @@ #define PCI_DEVICE_ID_SI_6306 0x6306 #define PCI_DEVICE_ID_SI_6326 0x6326 #define PCI_DEVICE_ID_SI_7001 0x7001 +#define PCI_DEVICE_ID_SI_7016 0x7016 #define PCI_VENDOR_ID_HP 0x103c #define PCI_DEVICE_ID_HP_DONNER_GFX 0x1008 @@ -508,6 +524,8 @@ #define PCI_DEVICE_ID_TI_1251A 0xac1d #define PCI_DEVICE_ID_TI_1211 0xac1e #define PCI_DEVICE_ID_TI_1251B 0xac1f +#define PCI_DEVICE_ID_TI_4410 0xac41 +#define PCI_DEVICE_ID_TI_4451 0xac42 #define PCI_DEVICE_ID_TI_1420 0xac51 #define PCI_VENDOR_ID_SONY 0x104d @@ -544,6 +562,7 @@ #define PCI_DEVICE_ID_PROMISE_20267 0x4d30 #define PCI_DEVICE_ID_PROMISE_20246 0x4d33 #define PCI_DEVICE_ID_PROMISE_20262 0x4d38 +#define PCI_DEVICE_ID_PROMISE_20268 0x4d68 #define PCI_DEVICE_ID_PROMISE_5300 0x5300 #define PCI_VENDOR_ID_N9 0x105d @@ -800,6 +819,8 @@ #define PCI_VENDOR_ID_IMS 0x10e0 #define PCI_DEVICE_ID_IMS_8849 0x8849 +#define PCI_DEVICE_ID_IMS_TT128 0x9128 +#define PCI_DEVICE_ID_IMS_TT3D 0x9135 #define PCI_VENDOR_ID_TEKRAM2 0x10e1 #define PCI_DEVICE_ID_TEKRAM2_690c 0x690c @@ -825,6 +846,9 @@ #define PCI_DEVICE_ID_REALTEK_8129 0x8129 #define PCI_DEVICE_ID_REALTEK_8139 0x8139 +#define PCI_VENDOR_ID_XILINX 0x10ee +#define PCI_DEVICE_ID_TURBOPAM 0x4020 + #define PCI_VENDOR_ID_TRUEVISION 0x10fa #define PCI_DEVICE_ID_TRUEVISION_T1000 0x000c @@ -1003,15 +1027,18 @@ #define PCI_DEVICE_ID_RENDITION_VERITE 0x0001 #define PCI_DEVICE_ID_RENDITION_VERITE2100 0x2000 -#define PCI_VENDOR_ID_SERVERWORKS 0x1166 -#define PCI_DEVICE_ID_SERVERWORKS_HE 0x0008 -#define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009 -#define PCI_DEVICE_ID_SERVERWORKS_CIOB30 0x0010 -#define PCI_DEVICE_ID_SERVERWORKS_CMIC_HE 0x0011 -#define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201 -#define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200 +#define PCI_VENDOR_ID_SERVERWORKS 0x1166 +#define PCI_DEVICE_ID_SERVERWORKS_HE 0x0008 +#define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009 +#define PCI_DEVICE_ID_SERVERWORKS_CIOB30 0x0010 +#define PCI_DEVICE_ID_SERVERWORKS_CMIC_HE 0x0011 +#define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201 +#define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200 #define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211 +#define PCI_DEVICE_ID_SERVERWORKS_CSB5IDE 0x0212 #define PCI_DEVICE_ID_SERVERWORKS_OSB4USB 0x0220 +#define PCI_DEVICE_ID_SERVERWORKS_CSB5USB PCI_DEVICE_ID_SERVERWORKS_OSB4USB +#define PCI_DEVICE_ID_SERVERWORKS_CSB5ISA 0x0230 #define PCI_VENDOR_ID_SBE 0x1176 #define PCI_DEVICE_ID_SBE_WANXL100 0x0301 @@ -1189,6 +1216,9 @@ #define PCI_VENDOR_ID_ROCKWELL 0x127A +#define PCI_VENDOR_ID_ITE 0x1283 +#define PCI_DEVICE_ID_ITE_IT8172G 0x8172 + /* formerly Platform Tech */ #define PCI_VENDOR_ID_ESS_OLD 0x1285 #define PCI_DEVICE_ID_ESS_ESS0100 0x0100 @@ -1299,6 +1329,9 @@ #define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2 0x0108 #define PCI_SUBDEVICE_ID_HYPERCOPE_PLEXUS 0x0109 +#define PCI_VENDOR_ID_KAWASAKI 0x136b +#define PCI_DEVICE_ID_MCHIP_KL5A72002 0xff01 + #define PCI_VENDOR_ID_LMC 0x1376 #define PCI_DEVICE_ID_LMC_HSSI 0x0003 #define PCI_DEVICE_ID_LMC_DS3 0x0004 @@ -1372,6 +1405,8 @@ #define PCI_DEVICE_ID_AIRONET_4500 0x4800 // drivers/net/aironet4500_card.c #define PCI_VENDOR_ID_TITAN 0x14D2 +#define PCI_DEVICE_ID_TITAN_110L 0x8011 +#define PCI_DEVICE_ID_TITAN_210L 0x8021 #define PCI_DEVICE_ID_TITAN_100 0xA001 #define PCI_DEVICE_ID_TITAN_200 0xA005 #define PCI_DEVICE_ID_TITAN_400 0xA003 @@ -1592,6 +1627,10 @@ #define PCI_VENDOR_ID_HOLTEK 0x9412 #define PCI_DEVICE_ID_HOLTEK_6565 0x6565 +#define PCI_VENDOR_ID_NETMOS 0x9710 +#define PCI_DEVICE_ID_NETMOS_9735 0x9735 +#define PCI_DEVICE_ID_NETMOS_9835 0x9835 + #define PCI_SUBVENDOR_ID_EXSYS 0xd84d #define PCI_SUBDEVICE_ID_EXSYS_4014 0x4014 diff --git a/include/linux/sysv_fs.h b/include/linux/sysv_fs.h index 4cff4260c939..00d314fb918e 100644 --- a/include/linux/sysv_fs.h +++ b/include/linux/sysv_fs.h @@ -7,7 +7,6 @@ /* This code assumes - - a little endian processor like 386, - sizeof(short) = 2, sizeof(int) = 4, sizeof(long) = 4, - alignof(short) = 2, alignof(long) = 4. */ @@ -26,27 +25,17 @@ /* Layout on disk */ /* ============== */ - -/* The block size is sb->sv_block_size which may be smaller than BLOCK_SIZE. */ - -/* zones (= data allocation units) are blocks */ - -/* On Coherent FS, 32 bit quantities are stored using (I quote the Coherent - manual) a "canonical byte ordering". This is the PDP-11 byte ordering: - x = 2^24 * byte3 + 2^16 * byte2 + 2^8 * byte1 + byte0 is stored - as { byte2, byte3, byte0, byte1 }. We need conversions. -*/ - -typedef u32 coh_ulong; - -static inline coh_ulong to_coh_ulong (u32 x) -{ - return ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16); -} - -static inline u32 from_coh_ulong (coh_ulong x) +static inline u32 PDP_swab(u32 x) { +#ifdef __LITTLE_ENDIAN return ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16); +#else +#ifdef __BIG_ENDIAN + return ((x & 0xff00ff) << 8) | ((x & 0xff00ff00) >> 8); +#else +#error BYTESEX +#endif +#endif } /* inode numbers are 16 bit */ @@ -103,12 +92,6 @@ struct xenix_super_block { }; -/* Xenix free list block on disk */ -struct xenix_freelist_chunk { - u16 fl_nfree; /* number of free blocks in fl_free, <= XENIX_NICFREE] */ - u32 fl_free[XENIX_NICFREE] __packed2__; -}; - /* SystemV FS comes in two variants: * sysv2: System V Release 2 (e.g. Microport), structure elements aligned(2). * sysv4: System V Release 4 (e.g. Consensys), structure elements aligned(4). @@ -148,12 +131,6 @@ struct sysv4_super_block { 2 for 1024 byte blocks */ }; -/* SystemV4 free list block on disk */ -struct sysv4_freelist_chunk { - u16 fl_nfree; /* number of free blocks in fl_free, <= SYSV_NICFREE] */ - u32 fl_free[SYSV_NICFREE]; -}; - /* SystemV2 super-block data on disk */ struct sysv2_super_block { u16 s_isize; /* index of first data zone */ @@ -182,10 +159,31 @@ struct sysv2_super_block { 2 for 1024 byte blocks */ }; -/* SystemV2 free list block on disk */ -struct sysv2_freelist_chunk { - u16 fl_nfree; /* number of free blocks in fl_free, <= SYSV_NICFREE] */ - u32 fl_free[SYSV_NICFREE] __packed2__; +/* V7 super-block data on disk */ +#define V7_NICINOD 100 /* number of inode cache entries */ +#define V7_NICFREE 50 /* number of free block list chunk entries */ +struct v7_super_block { + u16 s_isize; /* index of first data zone */ + u32 s_fsize __packed2__; /* total number of zones of this fs */ + /* the start of the free block list: */ + u16 s_nfree; /* number of free blocks in s_free, <= V7_NICFREE */ + u32 s_free[V7_NICFREE]; /* first free block list chunk */ + /* the cache of free inodes: */ + u16 s_ninode; /* number of free inodes in s_inode, <= V7_NICINOD */ + sysv_ino_t s_inode[V7_NICINOD]; /* some free inodes */ + /* locks, not used by Linux or V7: */ + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ + u32 s_time __packed2__; /* time of last super block update */ + /* the following fields are not maintained by V7: */ + u32 s_tfree __packed2__; /* total number of free zones */ + u16 s_tinode; /* total number of free inodes */ + u16 s_m; /* interleave factor */ + u16 s_n; /* interleave factor */ + char s_fname[6]; /* file system name */ + char s_fpack[6]; /* file system pack name */ }; /* Coherent super-block data on disk */ @@ -193,10 +191,10 @@ struct sysv2_freelist_chunk { #define COH_NICFREE 64 /* number of free block list chunk entries */ struct coh_super_block { u16 s_isize; /* index of first data zone */ - coh_ulong s_fsize __packed2__; /* total number of zones of this fs */ + u32 s_fsize __packed2__; /* total number of zones of this fs */ /* the start of the free block list: */ u16 s_nfree; /* number of free blocks in s_free, <= COH_NICFREE */ - coh_ulong s_free[COH_NICFREE] __packed2__; /* first free block list chunk */ + u32 s_free[COH_NICFREE] __packed2__; /* first free block list chunk */ /* the cache of free inodes: */ u16 s_ninode; /* number of free inodes in s_inode, <= COH_NICINOD */ sysv_ino_t s_inode[COH_NICINOD]; /* some free inodes */ @@ -205,8 +203,8 @@ struct coh_super_block { char s_ilock; /* lock during inode cache manipulation */ char s_fmod; /* super-block modified flag */ char s_ronly; /* flag whether fs is mounted read-only */ - coh_ulong s_time __packed2__; /* time of last super block update */ - coh_ulong s_tfree __packed2__; /* total number of free zones */ + u32 s_time __packed2__; /* time of last super block update */ + u32 s_tfree __packed2__; /* total number of free zones */ u16 s_tinode; /* total number of free inodes */ u16 s_interleave_m; /* interleave factor */ u16 s_interleave_n; @@ -215,13 +213,6 @@ struct coh_super_block { u32 s_unique; /* zero, not used */ }; -/* Coherent free list block on disk */ -struct coh_freelist_chunk { - u16 fl_nfree; /* number of free blocks in fl_free, <= COH_NICFREE] */ - u32 fl_free[COH_NICFREE] __packed2__; -}; - - /* SystemV/Coherent inode data on disk */ struct sysv_inode { @@ -237,8 +228,6 @@ struct sysv_inode { * then 1 triple indirection block. * Then maybe a "file generation number" ?? */ - /* devices */ - dev_t i_rdev; /* named pipes on Coherent */ struct { char p_addp[30]; @@ -300,9 +289,12 @@ extern inline unsigned short to_coh_imode(mode_t mode) } /* Admissible values for i_nlink: 0.._LINK_MAX */ -#define XENIX_LINK_MAX 126 /* ?? */ -#define SYSV_LINK_MAX 126 /* 127? 251? */ -#define COH_LINK_MAX 10000 /* max number of hard links to an inode */ +enum { + XENIX_LINK_MAX = 126, /* ?? */ + SYSV_LINK_MAX = 126, /* 127? 251? */ + V7_LINK_MAX = 126, /* ?? */ + COH_LINK_MAX = 10000, +}; /* The number of inodes per block is sb->sv_inodes_per_block = block_size / sizeof(struct sysv_inode) */ @@ -325,12 +317,16 @@ struct sysv_dir_entry { /* Operations */ /* ========== */ - /* identify the FS in memory */ -#define FSTYPE_XENIX 1 -#define FSTYPE_SYSV4 2 -#define FSTYPE_SYSV2 3 -#define FSTYPE_COH 4 +enum { + FSTYPE_NONE = 0, + FSTYPE_XENIX, + FSTYPE_SYSV4, + FSTYPE_SYSV2, + FSTYPE_COH, + FSTYPE_V7, + FSTYPE_END, +}; #define SYSV_MAGIC_BASE 0x012FF7B3 @@ -341,55 +337,112 @@ struct sysv_dir_entry { #ifdef __KERNEL__ -/* sv_get_hash_table(sb,dev,block) is equivalent to get_hash_table(dev,block,block_size) */ -static inline struct buffer_head * -sv_get_hash_table (struct super_block *sb, kdev_t dev, unsigned int block) -{ - return get_hash_table (dev, block + sb->sv_block_base, sb->sv_block_size); -} - -/* sv_getblk(sb,dev,block) is equivalent to getblk(dev,block,block_size) */ -static inline struct buffer_head * -sv_getblk (struct super_block *sb, kdev_t dev, unsigned int block) -{ - return getblk (dev, block + sb->sv_block_base, sb->sv_block_size); -} - -/* sv_bread(sb,dev,block) is equivalent to bread(dev,block,block_size) */ -static inline struct buffer_head * -sv_bread (struct super_block *sb, kdev_t dev, unsigned int block) -{ - return bread (dev, block + sb->sv_block_base, sb->sv_block_size); -} - +enum { + BYTESEX_LE, + BYTESEX_PDP, + BYTESEX_BE, +}; /* * Function prototypes */ -extern struct inode * sysv_new_inode(const struct inode * dir); -extern void sysv_free_inode(struct inode * inode); -extern unsigned long sysv_count_free_inodes(struct super_block *sb); -extern int sysv_new_block(struct super_block * sb); -extern void sysv_free_block(struct super_block * sb, unsigned int block); -extern unsigned long sysv_count_free_blocks(struct super_block *sb); - -extern struct buffer_head * sysv_file_bread(struct inode *, int, int); +extern struct inode * sysv_new_inode(const struct inode *, mode_t); +extern void sysv_free_inode(struct inode *); +extern unsigned long sysv_count_free_inodes(struct super_block *); +extern u32 sysv_new_block(struct super_block *); +extern void sysv_free_block(struct super_block *, u32); +extern unsigned long sysv_count_free_blocks(struct super_block *); extern void sysv_truncate(struct inode *); + extern void sysv_write_inode(struct inode *, int); extern int sysv_sync_inode(struct inode *); extern int sysv_sync_file(struct file *, struct dentry *, int); extern int sysv_notify_change(struct dentry *, struct iattr *); +extern void sysv_set_inode(struct inode *, dev_t); + +extern struct sysv_dir_entry *sysv_find_entry(struct dentry*, struct page**); +extern int sysv_add_link(struct dentry*, struct inode*); +extern int sysv_delete_entry(struct sysv_dir_entry*, struct page*); +extern int sysv_make_empty(struct inode*, struct inode*); +extern int sysv_empty_dir(struct inode*); +extern void sysv_set_link(struct sysv_dir_entry*, struct page*, struct inode*); +extern struct sysv_dir_entry *sysv_dotdot(struct inode*, struct page**); +extern ino_t sysv_inode_by_name(struct dentry*); extern struct inode_operations sysv_file_inode_operations; -extern struct inode_operations sysv_symlink_inode_operations; extern struct inode_operations sysv_dir_inode_operations; extern struct file_operations sysv_file_operations; extern struct file_operations sysv_dir_operations; extern struct address_space_operations sysv_aops; +extern struct super_operations sysv_sops; +extern struct dentry_operations sysv_dentry_operations; + +extern struct sysv_inode *sysv_raw_inode(struct super_block *, unsigned, struct buffer_head **); + +static inline void dirty_sb(struct super_block *sb) +{ + mark_buffer_dirty(sb->sv_bh1); + if (sb->sv_bh1 != sb->sv_bh2) + mark_buffer_dirty(sb->sv_bh2); + sb->s_dirt = 1; +} + +static inline u32 fs32_to_cpu(struct super_block *sb, u32 n) +{ + if (sb->sv_bytesex == BYTESEX_PDP) + return PDP_swab(n); + else if (sb->sv_bytesex == BYTESEX_LE) + return le32_to_cpu(n); + else + return be32_to_cpu(n); +} + +static inline u32 cpu_to_fs32(struct super_block *sb, u32 n) +{ + if (sb->sv_bytesex == BYTESEX_PDP) + return PDP_swab(n); + else if (sb->sv_bytesex == BYTESEX_LE) + return cpu_to_le32(n); + else + return cpu_to_be32(n); +} + +static inline u32 fs32_add(struct super_block *sb, u32 *n, int d) +{ + if (sb->sv_bytesex == BYTESEX_PDP) + return *n = PDP_swab(PDP_swab(*n)+d); + else if (sb->sv_bytesex == BYTESEX_LE) + return *n = cpu_to_le32(le32_to_cpu(*n)+d); + else + return *n = cpu_to_be32(be32_to_cpu(*n)+d); +} + +static inline u16 fs16_to_cpu(struct super_block *sb, u16 n) +{ + if (sb->sv_bytesex != BYTESEX_BE) + return le16_to_cpu(n); + else + return be16_to_cpu(n); +} + +static inline u16 cpu_to_fs16(struct super_block *sb, u16 n) +{ + if (sb->sv_bytesex != BYTESEX_BE) + return cpu_to_le16(n); + else + return cpu_to_be16(n); +} + +static inline u16 fs16_add(struct super_block *sb, u16 *n, int d) +{ + if (sb->sv_bytesex != BYTESEX_BE) + return *n = cpu_to_le16(le16_to_cpu(*n)+d); + else + return *n = cpu_to_be16(be16_to_cpu(*n)+d); +} #endif /* __KERNEL__ */ #endif - diff --git a/include/linux/sysv_fs_i.h b/include/linux/sysv_fs_i.h index 990b3543fdcd..08eff4449aff 100644 --- a/include/linux/sysv_fs_i.h +++ b/include/linux/sysv_fs_i.h @@ -2,7 +2,7 @@ #define _SYSV_FS_I /* - * SystemV/Coherent FS inode data in memory + * SystemV/V7/Coherent FS inode data in memory */ struct sysv_inode_info { u32 i_data[10+1+1+1]; /* zone numbers: max. 10 data blocks, diff --git a/include/linux/sysv_fs_sb.h b/include/linux/sysv_fs_sb.h index df886f651c02..fe324c96df84 100644 --- a/include/linux/sysv_fs_sb.h +++ b/include/linux/sysv_fs_sb.h @@ -2,8 +2,8 @@ #define _SYSV_FS_SB /* - * SystemV/Coherent super-block data in memory - * The SystemV/Coherent superblock contains dynamic data (it gets modified + * SystemV/V7/Coherent super-block data in memory + * The SystemV/V7/Coherent superblock contains dynamic data (it gets modified * while the system is running). This is in contrast to the Minix and Berkeley * filesystems (where the superblock is never modified). This affects the * sync() operation: we must keep the superblock in a disk buffer and use this @@ -12,12 +12,7 @@ struct sysv_sb_info { int s_type; /* file system type: FSTYPE_{XENIX|SYSV|COH} */ - unsigned int s_block_size; /* zone size, = 512 or = 1024 */ - unsigned int s_block_size_1; /* block_size - 1 */ - unsigned int s_block_size_bits; /* log2(block_size) */ - unsigned int s_block_size_inc_bits; /* log2(block_size/BLOCK_SIZE) if >0 */ - unsigned int s_block_size_dec_bits; /* log2(BLOCK_SIZE/block_size) if >0 */ - char s_convert; /* flag whether byte ordering requires conversion */ + char s_bytesex; /* bytesex (le/be/pdp) */ char s_kludge_symlinks; /* flag whether symlinks have a kludgey mode */ char s_truncate; /* if 1: names > SYSV_NAMELEN chars are truncated */ /* if 0: they are disallowed (ENAMETOOLONG) */ @@ -26,19 +21,8 @@ struct sysv_sb_info { unsigned int s_inodes_per_block_1; /* inodes_per_block - 1 */ unsigned int s_inodes_per_block_bits; /* log2(inodes_per_block) */ unsigned int s_ind_per_block; /* number of indirections per block */ - unsigned int s_ind_per_block_1; /* ind_per_block - 1 */ unsigned int s_ind_per_block_bits; /* log2(ind_per_block) */ unsigned int s_ind_per_block_2; /* ind_per_block ^ 2 */ - unsigned int s_ind_per_block_2_1; /* ind_per_block ^ 2 - 1 */ - unsigned int s_ind_per_block_2_bits; /* log2(ind_per_block^2) */ - unsigned int s_ind_per_block_3; /* ind_per_block ^ 3 */ - unsigned int s_ind_per_block_block_size_1; /* ind_per_block*block_size - 1 */ - unsigned int s_ind_per_block_block_size_bits; /* log2(ind_per_block*block_size) */ - unsigned int s_ind_per_block_2_block_size_1; /* ind_per_block^2 * block_size - 1 */ - unsigned int s_ind_per_block_2_block_size_bits; /* log2(ind_per_block^2 * block_size) */ - unsigned int s_ind0_size; /* 10 * block_size */ - unsigned int s_ind1_size; /* (10 + ipb) * block_size */ - unsigned int s_ind2_size; /* (10 + ipb + ipb^2) * block_size */ unsigned int s_toobig_block; /* 10 + ipb + ipb^2 + ipb^3 */ unsigned int s_block_base; /* physical block number of block 0 */ unsigned short s_fic_size; /* free inode cache size, NICINOD */ @@ -53,9 +37,9 @@ struct sysv_sb_info { u16 *s_sb_fic_count; /* pointer to s_sbd->s_ninode */ u16 *s_sb_fic_inodes; /* pointer to s_sbd->s_inode */ u16 *s_sb_total_free_inodes; /* pointer to s_sbd->s_tinode */ - u16 *s_sb_flc_count; /* pointer to s_sbd->s_nfree */ - u32 *s_sb_flc_blocks; /* pointer to s_sbd->s_free */ - u32 *s_sb_total_free_blocks;/* pointer to s_sbd->s_tfree */ + u16 *s_bcache_count; /* pointer to s_sbd->s_nfree */ + u32 *s_bcache; /* pointer to s_sbd->s_free */ + u32 *s_free_blocks; /* pointer to s_sbd->s_tfree */ u32 *s_sb_time; /* pointer to s_sbd->s_time */ u32 *s_sb_state; /* pointer to s_sbd->s_state, only FSTYPE_SYSV */ /* We keep those superblock entities that don't change here; @@ -65,17 +49,13 @@ struct sysv_sb_info { u32 s_ninodes; /* total number of inodes */ u32 s_ndatazones; /* total number of data zones */ u32 s_nzones; /* same as s_sbd->s_fsize */ + u16 s_namelen; /* max length of dir entry */ }; -/* The fields s_ind_per_block_2_1, s_toobig_block are currently unused. */ +/* The field s_toobig_block is currently unused. */ /* sv_ == u.sysv_sb.s_ */ #define sv_type u.sysv_sb.s_type -#define sv_block_size u.sysv_sb.s_block_size -#define sv_block_size_1 u.sysv_sb.s_block_size_1 -#define sv_block_size_bits u.sysv_sb.s_block_size_bits -#define sv_block_size_inc_bits u.sysv_sb.s_block_size_inc_bits -#define sv_block_size_dec_bits u.sysv_sb.s_block_size_dec_bits -#define sv_convert u.sysv_sb.s_convert +#define sv_bytesex u.sysv_sb.s_bytesex #define sv_kludge_symlinks u.sysv_sb.s_kludge_symlinks #define sv_truncate u.sysv_sb.s_truncate #define sv_link_max u.sysv_sb.s_link_max @@ -83,19 +63,8 @@ struct sysv_sb_info { #define sv_inodes_per_block_1 u.sysv_sb.s_inodes_per_block_1 #define sv_inodes_per_block_bits u.sysv_sb.s_inodes_per_block_bits #define sv_ind_per_block u.sysv_sb.s_ind_per_block -#define sv_ind_per_block_1 u.sysv_sb.s_ind_per_block_1 #define sv_ind_per_block_bits u.sysv_sb.s_ind_per_block_bits #define sv_ind_per_block_2 u.sysv_sb.s_ind_per_block_2 -#define sv_ind_per_block_2_1 u.sysv_sb.s_ind_per_block_2_1 -#define sv_ind_per_block_2_bits u.sysv_sb.s_ind_per_block_2_bits -#define sv_ind_per_block_3 u.sysv_sb.s_ind_per_block_3 -#define sv_ind_per_block_block_size_1 u.sysv_sb.s_ind_per_block_block_size_1 -#define sv_ind_per_block_block_size_bits u.sysv_sb.s_ind_per_block_block_size_bits -#define sv_ind_per_block_2_block_size_1 u.sysv_sb.s_ind_per_block_2_block_size_1 -#define sv_ind_per_block_2_block_size_bits u.sysv_sb.s_ind_per_block_2_block_size_bits -#define sv_ind0_size u.sysv_sb.s_ind0_size -#define sv_ind1_size u.sysv_sb.s_ind1_size -#define sv_ind2_size u.sysv_sb.s_ind2_size #define sv_toobig_block u.sysv_sb.s_toobig_block #define sv_block_base u.sysv_sb.s_block_base #define sv_fic_size u.sysv_sb.s_fic_size @@ -107,9 +76,9 @@ struct sysv_sb_info { #define sv_sb_fic_count u.sysv_sb.s_sb_fic_count #define sv_sb_fic_inodes u.sysv_sb.s_sb_fic_inodes #define sv_sb_total_free_inodes u.sysv_sb.s_sb_total_free_inodes -#define sv_sb_flc_count u.sysv_sb.s_sb_flc_count -#define sv_sb_flc_blocks u.sysv_sb.s_sb_flc_blocks -#define sv_sb_total_free_blocks u.sysv_sb.s_sb_total_free_blocks +#define sv_bcache_count u.sysv_sb.s_bcache_count +#define sv_bcache u.sysv_sb.s_bcache +#define sv_free_blocks u.sysv_sb.s_free_blocks #define sv_sb_time u.sysv_sb.s_sb_time #define sv_sb_state u.sysv_sb.s_sb_state #define sv_firstinodezone u.sysv_sb.s_firstinodezone @@ -117,6 +86,6 @@ struct sysv_sb_info { #define sv_ninodes u.sysv_sb.s_ninodes #define sv_ndatazones u.sysv_sb.s_ndatazones #define sv_nzones u.sysv_sb.s_nzones +#define sv_namelen u.sysv_sb.s_namelen #endif - diff --git a/include/linux/udf_fs.h b/include/linux/udf_fs.h index 4edb0a337318..736d617f0a68 100644 --- a/include/linux/udf_fs.h +++ b/include/linux/udf_fs.h @@ -37,8 +37,8 @@ #define UDF_PREALLOCATE #define UDF_DEFAULT_PREALLOC_BLOCKS 8 -#define UDFFS_DATE "2001/06/06" -#define UDFFS_VERSION "0.9.4" +#define UDFFS_DATE "2001/06/13" +#define UDFFS_VERSION "0.9.4.1" #if !defined(UDFFS_RW) diff --git a/include/linux/udf_fs_i.h b/include/linux/udf_fs_i.h index 84c481cd390b..3d48fced7cc1 100644 --- a/include/linux/udf_fs_i.h +++ b/include/linux/udf_fs_i.h @@ -30,9 +30,10 @@ typedef struct struct udf_inode_info { - long i_uatime; long i_umtime; long i_uctime; + long i_crtime; + long i_ucrtime; /* Physical address of inode */ lb_addr i_location; __u64 i_unique; diff --git a/include/linux/udf_udf.h b/include/linux/udf_udf.h index 4fa4b3df754e..6b9df04be3e1 100644 --- a/include/linux/udf_udf.h +++ b/include/linux/udf_udf.h @@ -162,6 +162,10 @@ struct VirtualAllocationTable20 { Uint32 vatEntry[0]; }; +/* ----------- 2.01 ------------- */ +/* UDF 2.01 6.11 */ +#define FILE_TYPE_REALTIME 0xf9U + /* Sparing maps, see UDF 1.5 2.2.11 */ typedef struct { Uint32 origLocation; diff --git a/mm/bootmem.c b/mm/bootmem.c index fc0fd30f2067..a34bdab16490 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -1,5 +1,5 @@ /* - * linux/mm/initmem.c + * linux/mm/bootmem.c * * Copyright (C) 1999 Ingo Molnar * Discontiguous memory support, Kanoj Sarcar, SGI, Nov 1999 diff --git a/mm/mmap.c b/mm/mmap.c index 6f539de6dce2..707e672a0c96 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -66,14 +66,6 @@ int vm_enough_memory(long pages) free += nr_swap_pages; /* - * This double-counts: the nrpages are both in the page-cache - * and in the swapper space. At the same time, this compensates - * for the swap-space over-allocation (ie "nr_swap_pages" being - * too small. - */ - free += swapper_space.nrpages; - - /* * The code below doesn't account for free space in the inode * and dentry slab cache, slab cache fragmentation, inodes and * dentries which will become freeable under VM load, etc. diff --git a/mm/numa.c b/mm/numa.c index be2ffc48d8f2..662e7c544950 100644 --- a/mm/numa.c +++ b/mm/numa.c @@ -92,7 +92,7 @@ static struct page * alloc_pages_pgdat(pg_data_t *pgdat, int gfp_mask, * This can be refined. Currently, tries to do round robin, instead * should do concentratic circle search, starting from current node. */ -struct page * _alloc_pages(int gfp_mask, unsigned long order) +struct page * _alloc_pages(unsigned int gfp_mask, unsigned long order) { struct page *ret = 0; pg_data_t *start, *temp; diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c index e6dcda83d93f..a0ffd6afd4c9 100644 --- a/net/ax25/ax25_ip.c +++ b/net/ax25/ax25_ip.c @@ -160,7 +160,7 @@ int ax25_rebuild_header(struct sk_buff *skb) dst_c = *dst; skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */ - skb->nh.raw = skb->data; + ourskb->nh.raw = ourskb->data; ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c, &dst_c, route->digipeat, dev); diff --git a/net/ipx/af_spx.c b/net/ipx/af_spx.c index 0a6cdd225548..78edf8786614 100644 --- a/net/ipx/af_spx.c +++ b/net/ipx/af_spx.c @@ -398,7 +398,7 @@ static int spx_route_skb(struct spx_opt *pdata, struct sk_buff *skb, int type) pdata->retransmit.expires = jiffies + spx_calc_rtt(0); add_timer(&pdata->retransmit); - skb2 = skb_clone(skb, GFP_NOFS); /* Why? Why not GFP_KERNEL? */ + skb2 = skb_clone(skb, GFP_NOIO); if(skb2 == NULL) return -ENOBUFS; skb_queue_tail(&pdata->retransmit_queue, skb2); diff --git a/scripts/Configure b/scripts/Configure index f931c4cbfd04..58375f239bbc 100644 --- a/scripts/Configure +++ b/scripts/Configure @@ -92,6 +92,7 @@ ${var}:\\ /^#/b /^[^ ]/q + /<file:\\([^>]*\\)>/s//\\1/g p }" Documentation/Configure.help) if [ -z "$text" ] diff --git a/scripts/Menuconfig b/scripts/Menuconfig index b1d21bb0b666..b48d36bcb974 100644 --- a/scripts/Menuconfig +++ b/scripts/Menuconfig @@ -376,6 +376,7 @@ ${var}:\\ /^#/b /^[^ ]/q s/^ // + /<file:\\([^>]*\\)>/s//\\1/g p }" Documentation/Configure.help) diff --git a/scripts/header.tk b/scripts/header.tk index 94963425a9a5..2cc9c7e534e9 100644 --- a/scripts/header.tk +++ b/scripts/header.tk @@ -466,6 +466,7 @@ ${var}:\\ /^#/b /^\[^ \]/q s/^ // + /<file:\\(\[^>\]*\\)>/s//\\1/g p } " Documentation/Configure.help] diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 32e4d97929e4..1f9a4bdf3a25 100644 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -18,6 +18,11 @@ use strict; # Functions prototyped as foo(void) same as foo() # Stop eval'ing where we don't need to. # -- huggie@earth.li + +# 27/06/2001 - Allowed whitespace after initial "/**" and +# allowed comments before function declarations. +# -- Christian Kreibich <ck@whoop.org> + # Still to do: # - add perldoc documentation # - Look more closely at some of the scarier bits :) @@ -825,7 +830,7 @@ $section = ""; $doc_special = "\@\%\$\&"; -$doc_start = "^/\\*\\*\$"; +$doc_start = "^/\\*\\*\\s*\$"; # Allow whitespace at end of comment start. $doc_end = "\\*/"; $doc_com = "\\s*\\*\\s*"; $doc_func = $doc_com."(\\w+):?"; @@ -975,7 +980,7 @@ sub process_file($) { elsif (/([^\{]*)/) { $prototype .= $1; } - if (/\{/ || /\#/) { # added for #define AK + if (/\{/ || /\#/ || /;/) { # added for #define AK, ';' added for declarations. $prototype =~ s@/\*.*?\*/@@gos; # strip comments. $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's. $prototype =~ s@^ +@@gos; # strip leading spaces |
