-mm1 --- diff/CREDITS 2004-02-09 10:36:07.000000000 +0000 +++ source/CREDITS 2004-02-09 10:39:51.000000000 +0000 @@ -818,6 +818,11 @@ S: Sunnyvale, CA 94087 S: USA +N: Bruno Ducrot +E: ducrot@poupinou.org +D: CPUFreq and ACPI bugfixes. +S: Mougin, France + N: Don Dugger E: n0ano@valinux.com D: Linux/IA-64 --- diff/Documentation/Changes 2004-01-19 10:22:54.000000000 +0000 +++ source/Documentation/Changes 2004-02-09 10:39:51.000000000 +0000 @@ -216,13 +216,6 @@ as root before you can use this. You'll probably also want to get the user-space microcode_ctl utility to use with this. -If you have compiled the driver as a module you may need to add -the following line: - -alias char-major-10-184 microcode - -to your /etc/modules.conf file. - Powertweak ---------- @@ -257,17 +250,6 @@ as root. -If you build ppp support as modules, you will need the following in -your /etc/modules.conf file: - -alias char-major-108 ppp_generic -alias /dev/ppp ppp_generic -alias tty-ldisc-3 ppp_async -alias tty-ldisc-14 ppp_synctty -alias ppp-compress-21 bsd_comp -alias ppp-compress-24 ppp_deflate -alias ppp-compress-26 ppp_deflate - If you use devfsd and build ppp support as modules, you will need the following in your /etc/devfsd.conf file: --- diff/Documentation/DMA-API.txt 2003-06-09 14:18:17.000000000 +0100 +++ source/Documentation/DMA-API.txt 2004-02-09 10:39:51.000000000 +0000 @@ -20,6 +20,10 @@ To get the pci_ API, you must #include To get the dma_ API, you must #include + +Part Ia - Using large dma-coherent buffers +------------------------------------------ + void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, int flag) @@ -42,6 +46,7 @@ Note: consistent memory can be expensive on some platforms, and the minimum allocation length may be as big as a page, so you should consolidate your requests for consistent memory as much as possible. +The simplest way to do that is to use the dma_pool calls (see below). The flag parameter (dma_alloc_coherent only) allows the caller to specify the GFP_ flags (see kmalloc) for the allocation (the @@ -61,6 +66,79 @@ consistent allocate. cpu_addr must be the virtual address returned by the consistent allocate + +Part Ib - Using small dma-coherent buffers +------------------------------------------ + +To get this part of the dma_ API, you must #include + +Many drivers need lots of small dma-coherent memory regions for DMA +descriptors or I/O buffers. Rather than allocating in units of a page +or more using dma_alloc_coherent(), you can use DMA pools. These work +much like a kmem_cache_t, except that they use the dma-coherent allocator +not __get_free_pages(). Also, they understand common hardware constraints +for alignment, like queue heads needing to be aligned on N byte boundaries. + + + struct dma_pool * + dma_pool_create(const char *name, struct device *dev, + size_t size, size_t align, size_t alloc); + + struct pci_pool * + pci_pool_create(const char *name, struct pci_device *dev, + size_t size, size_t align, size_t alloc); + +The pool create() routines initialize a pool of dma-coherent buffers +for use with a given device. It must be called in a context which +can sleep. + +The "name" is for diagnostics (like a kmem_cache_t name); dev and size +are like what you'd pass to dma_alloc_coherent(). The device's hardware +alignment requirement for this type of data is "align" (which is expressed +in bytes, and must be a power of two). If your device has no boundary +crossing restrictions, pass 0 for alloc; passing 4096 says memory allocated +from this pool must not cross 4KByte boundaries. + + + void *dma_pool_alloc(struct dma_pool *pool, int gfp_flags, + dma_addr_t *dma_handle); + + void *pci_pool_alloc(struct pci_pool *pool, int gfp_flags, + dma_addr_t *dma_handle); + +This allocates memory from the pool; the returned memory will meet the size +and alignment requirements specified at creation time. Pass GFP_ATOMIC to +prevent blocking, or if it's permitted (not in_interrupt, not holding SMP locks) +pass GFP_KERNEL to allow blocking. Like dma_alloc_coherent(), this returns +two values: an address usable by the cpu, and the dma address usable by the +pool's device. + + + void dma_pool_free(struct dma_pool *pool, void *vaddr, + dma_addr_t addr); + + void pci_pool_free(struct pci_pool *pool, void *vaddr, + dma_addr_t addr); + +This puts memory back into the pool. The pool is what was passed to +the the pool allocation routine; the cpu and dma addresses are what +were returned when that routine allocated the memory being freed. + + + void dma_pool_destroy(struct dma_pool *pool); + + void pci_pool_destroy(struct pci_pool *pool); + +The pool destroy() routines free the resources of the pool. They must be +called in a context which can sleep. Make sure you've freed all allocated +memory back to the pool before you destroy it. While pci_pool_destroy() +may not be called in interrupt context, it's perfectly safe to do that with +dma_pool_destroy(). + + +Part Ic - DMA addressing limitations +------------------------------------ + int dma_supported(struct device *dev, u64 mask) int @@ -86,6 +164,10 @@ Returns: 1 if successful and 0 if not + +Part Id - Streaming DMA mappings +-------------------------------- + dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction direction) @@ -254,6 +336,7 @@ See also dma_map_single(). + Part II - Advanced dma_ usage ----------------------------- --- diff/Documentation/DocBook/deviceiobook.tmpl 2003-05-21 11:49:45.000000000 +0100 +++ source/Documentation/DocBook/deviceiobook.tmpl 2004-02-09 10:39:51.000000000 +0000 @@ -126,7 +126,9 @@ The functions are named readb, readw, readl, - readq, writeb, + readq, readb_relaxed, + readw_relaxed, readl_relaxed, + readq_relaxed, writeb, writew, writel and writeq. @@ -159,6 +161,18 @@ author cares. This kind of property cannot be hidden from driver writers in the API. + + + PCI ordering rules also guarantee that PIO read responses arrive + after any outstanding DMA writes on that bus, since for some devices + the result of a readb call may signal to the + driver that a DMA transaction is complete. In many cases, however, + the driver may want to indicate that the next + readb call has no relation to any previous DMA + writes performed by the device. The driver can use + readb_relaxed for these cases, although only + some platforms will honor the relaxed semantics. + --- diff/Documentation/SubmittingPatches 2004-02-09 10:36:07.000000000 +0000 +++ source/Documentation/SubmittingPatches 2004-02-09 10:39:52.000000000 +0000 @@ -241,7 +241,7 @@ Simple example, of poor code: - dev = init_etherdev (NULL, 0); + dev = alloc_etherdev (sizeof(struct funky_private)); if (!dev) return -ENODEV; #ifdef CONFIG_NET_FUNKINESS @@ -256,7 +256,7 @@ #endif (in the code itself) - dev = init_etherdev (NULL, 0); + dev = alloc_etherdev (sizeof(struct funky_private)); if (!dev) return -ENODEV; init_funky_net(dev); --- diff/Documentation/as-iosched.txt 2003-09-30 15:46:10.000000000 +0100 +++ source/Documentation/as-iosched.txt 2004-02-09 10:39:51.000000000 +0000 @@ -11,6 +11,15 @@ me. Database users don't bother unless you're willing to test a lot of patches from me ;) its a known issue. +Also, users with hardware RAID controllers, doing striping, may find +highly variable performance results with using the as-iosched. The +as-iosched anticipatory implementation is based on the notion that a disk +device has only one physical seeking head. A striped RAID controller +actually has a head for each physical device in the logical RAID device. + +However, setting the antic_expire (see tunable parameters below) produces +very similar behavior to the deadline IO scheduler. + Selecting IO schedulers ----------------------- @@ -19,6 +28,107 @@ globally at boot time only presently. +Anticipatory IO scheduler Policies +---------------------------------- +The as-iosched implementation implements several layers of policies +to determine when an IO request is dispatched to the disk controller. +Here are the policies outlined, in order of application. + +1. one-way Elevator algorithm. + +The elevator algorithm is similar to that used in deadline scheduler, with +the addition that it allows limited backward movement of the elevator +(i.e. seeks backwards). A seek backwards can occur when choosing between +two IO requests where one is behind the elevator's current position, and +the other is in front of the elevator's position. If the seek distance to +the request in back of the elevator is less than half the seek distance to +the request in front of the elevator, then the request in back can be chosen. +Backward seeks are also limited to a maximum of MAXBACK (1024*1024) sectors. +This favors forward movement of the elevator, while allowing opportunistic +"short" backward seeks. + +2. FIFO expiration times for reads and for writes. + +This is again very similar to the deadline IO scheduler. The expiration +times for requests on these lists is tunable using the parameters read_expire +and write_expire discussed below. When a read or a write expires in this way, +the IO scheduler will interrupt its current elevator sweep or read anticipation +to service the expired request. + +3. Read and write request batching + +A batch is a collection of read requests or a collection of write +requests. The as scheduler alternates dispatching read and write batches +to the driver. In the case a read batch, the scheduler submits read +requests to the driver as long as there are read requests to submit, and +the read batch time limit has not been exceeded (read_batch_expire). +The read batch time limit begins counting down only when there are +competing write requests pending. + +In the case of a write batch, the scheduler submits write requests to +the driver as long as there are write requests available, and the +write batch time limit has not been exceeded (write_batch_expire). +However, the length of write batches will be gradually shortened +when read batches frequently exceed their time limit. + +When changing between batch types, the scheduler waits for all requests +from the previous batch to complete before scheduling requests for the +next batch. + +The read and write fifo expiration times described in policy 2 above +are checked only when in scheduling IO of a batch for the corresponding +(read/write) type. So for example, the read FIFO timeout values are +tested only during read batches. Likewise, the write FIFO timeout +values are tested only during write batches. For this reason, +it is generally not recommended for the read batch time +to be longer than the write expiration time, nor for the write batch +time to exceed the read expiration time (see tunable parameters below). + +When the IO scheduler changes from a read to a write batch, +it begins the elevator from the request that is on the head of the +write expiration FIFO. Likewise, when changing from a write batch to +a read batch, scheduler begins the elevator from the first entry +on the read expiration FIFO. + +4. Read anticipation. + +Read anticipation occurs only when scheduling a read batch. +This implementation of read anticipation allows only one read request +to be dispatched to the disk controller at a time. In +contrast, many write requests may be dispatched to the disk controller +at a time during a write batch. It is this characteristic that can make +the anticipatory scheduler perform anomalously with controllers supporting +TCQ, or with hardware striped RAID devices. Setting the antic_expire +queue paramter (see below) to zero disables this behavior, and the anticipatory +scheduler behaves essentially like the deadline scheduler. + +When read anticipation is enabled (antic_expire is not zero), reads +are dispatched to the disk controller one at a time. +At the end of each read request, the IO scheduler examines its next +candidate read request from its sorted read list. If that next request +is from the same process as the request that just completed, +or if the next request in the queue is "very close" to the +just completed request, it is dispatched immediately. Otherwise, +statistics (average think time, average seek distance) on the process +that submitted the just completed request are examined. If it seems +likely that that process will submit another request soon, and that +request is likely to be near the just completed request, then the IO +scheduler will stop dispatching more read requests for up time (antic_expire) +milliseconds, hoping that process will submit a new request near the one +that just completed. If such a request is made, then it is dispatched +immediately. If the antic_expire wait time expires, then the IO scheduler +will dispatch the next read request from the sorted read queue. + +To decide whether an anticipatory wait is worthwhile, the scheduler +maintains statistics for each process that can be used to compute +mean "think time" (the time between read requests), and mean seek +distance for that process. One observation is that these statistics +are associated with each process, but those statistics are not associated +with a specific IO device. So for example, if a process is doing IO +on several file systems on separate devices, the statistics will be +a combination of IO behavior from all those devices. + + Tuning the anticipatory IO scheduler ------------------------------------ When using 'as', the anticipatory IO scheduler there are 5 parameters under @@ -26,17 +136,18 @@ The parameters are: * read_expire - Controls how long until a request becomes "expired". It also controls the + Controls how long until a read request becomes "expired". It also controls the interval between which expired requests are served, so set to 50, a request might take anywhere < 100ms to be serviced _if_ it is the next on the - expired list. Obviously it won't make the disk go faster. The result - basically equates to the timeslice a single reader gets in the presence of - other IO. 100*((seek time / read_expire) + 1) is very roughly the % - streaming read efficiency your disk should get with multiple readers. - + expired list. Obviously request expiration strategies won't make the disk + go faster. The result basically equates to the timeslice a single reader + gets in the presence of other IO. 100*((seek time / read_expire) + 1) is + very roughly the % streaming read efficiency your disk should get with + multiple readers. + * read_batch_expire Controls how much time a batch of reads is given before pending writes are - served. Higher value is more efficient. This might be set below read_expire + served. A higher value is more efficient. This might be set below read_expire if writes are to be given higher priority than reads, but reads are to be as efficient as possible when there are no writes. Generally though, it should be some multiple of read_expire. @@ -45,7 +156,8 @@ * write_batch_expire are equivalent to the above, for writes. * antic_expire - Controls the maximum amount of time we can anticipate a good read before + Controls the maximum amount of time we can anticipate a good read (one + with a short seek distance from the most recently completed request) before giving up. Many other factors may cause anticipation to be stopped early, or some processes will not be "anticipated" at all. Should be a bit higher for big seek time devices though not a linear correspondence - most --- diff/Documentation/binfmt_misc.txt 2003-10-09 09:47:33.000000000 +0100 +++ source/Documentation/binfmt_misc.txt 2004-02-09 10:39:51.000000000 +0000 @@ -15,7 +15,7 @@ mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc To actually register a new binary type, you have to set up a string looking like -:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon +:name:type:offset:magic:mask:interpreter:flags (where you can choose the ':' upon your needs) and echo it to /proc/sys/fs/binfmt_misc/register. Here is what the fields mean: - 'name' is an identifier string. A new /proc file will be created with this @@ -34,6 +34,18 @@ The mask is anded with the byte sequence of the file. - 'interpreter' is the program that should be invoked with the binary as first argument (specify the full path) + - 'flags' is an optional field that controls several aspects of the invocation + of the interpreter. It is a string of capital letters, each controls a certain + aspect. The following flags are supported - + 'P' - preserve-argv[0]. Legacy behavior of binfmt_misc is to overwrite the + original argv[0] with the full path to the binary. When this flag is + included, binfmt_misc will add an argument to the argument vector for + this purpose, thus preserving the original argv[0]. + 'O' - open-binary. Legacy behavior of binfmt_misc is to pass the full path + of the binary to the interpreter as an argument. When this flag is + included, binfmt_misc will open the file for reading and pass its + descriptor as argument, instead of the full path, thus allowing the + interpreter to execute non-readable binaries. There are some restrictions: - the whole register string may not exceed 255 characters @@ -83,9 +95,9 @@ write a wrapper script for it. See Documentation/java.txt for an example. -Your interpreter should NOT look in the PATH for the filename; the -kernel passes it the full filename to use. Using the PATH can cause -unexpected behaviour and be a security hazard. +Your interpreter should NOT look in the PATH for the filename; the kernel +passes it the full filename (or the file descriptor) to use. Using $PATH can +cause unexpected behaviour and can be a security hazard. There is a web page about binfmt_misc at --- diff/Documentation/cciss.txt 2003-05-21 11:49:54.000000000 +0100 +++ source/Documentation/cciss.txt 2004-02-09 10:39:51.000000000 +0000 @@ -13,6 +13,7 @@ * SA 642 * SA 6400 * SA 6400 U320 Expansion Module + * SA 6i If nodes are not already created in the /dev/cciss directory --- diff/Documentation/computone.txt 2003-08-20 14:16:23.000000000 +0100 +++ source/Documentation/computone.txt 2004-02-09 10:39:51.000000000 +0000 @@ -41,11 +41,11 @@ Note the hardware address from the Computone ISA cards installed into the system. These are required for editing ip2.c or editing - /etc/modules.conf, or for specification on the modprobe + /etc/modprobe.conf, or for specification on the modprobe command line. - Note that the /etc/modules.conf file is named /etc/conf.modules - with older versions of the module utilities. + Note that the /etc/modules.conf should be used for older (pre-2.6) + kernels. Software - @@ -58,7 +58,7 @@ c) Set address on ISA cards then: edit /usr/src/linux/drivers/char/ip2.c if needed or - edit /etc/modules.conf if needed (module). + edit /etc/modprobe.conf if needed (module). or both to match this setting. d) Run "make modules" e) Run "make modules_install" @@ -145,11 +145,11 @@ selects polled mode). If no base addresses are specified the defaults in ip2.c are used. If you are autoloading the driver module with kerneld or kmod the base addresses and interrupt number must also be set in ip2.c -and recompile or just insert and options line in /etc/modules.conf or both. +and recompile or just insert and options line in /etc/modprobe.conf or both. The options line is equivalent to the command line and takes precidence over what is in ip2.c. -/etc/modules.conf sample: +/etc/modprobe.conf sample: options ip2 io=1,0x328 irq=1,10 alias char-major-71 ip2 alias char-major-72 ip2 --- diff/Documentation/crypto/api-intro.txt 2003-10-09 09:47:33.000000000 +0100 +++ source/Documentation/crypto/api-intro.txt 2004-02-09 10:39:51.000000000 +0000 @@ -68,7 +68,7 @@ CONFIGURATION NOTES As Triple DES is part of the DES module, for those using modular builds, -add the following line to /etc/modules.conf: +add the following line to /etc/modprobe.conf: alias des3_ede des --- diff/Documentation/digiboard.txt 2003-10-09 09:47:16.000000000 +0100 +++ source/Documentation/digiboard.txt 2004-02-09 10:39:51.000000000 +0000 @@ -24,7 +24,7 @@ The pcxx driver can be configured using the command line feature while loading the kernel with LILO or LOADLIN or, if built as a module, with arguments to insmod and modprobe or with parameters in -/etc/modules.conf for modprobe and kerneld. +/etc/modprobe.conf for modprobe and kerneld. After configuring the driver you need to create the device special files as described in "Device file creation:" below and set the appropriate @@ -91,13 +91,13 @@ The remaining board still uses ttyD8-ttyD15 and cud8-cud15. -Example line for /etc/modules.conf for use with kerneld and as default +Example line for /etc/modprobe.conf for use with kerneld and as default parameters for modprobe: options pcxx io=0x200 numports=8 -For kerneld to work you will likely need to add these two lines to your -/etc/modules.conf: +For kmod to work you will likely need to add these two lines to your +/etc/modprobe.conf: alias char-major-22 pcxx alias char-major-23 pcxx --- diff/Documentation/fb/intel810.txt 2003-01-02 10:43:02.000000000 +0000 +++ source/Documentation/fb/intel810.txt 2004-02-09 10:39:51.000000000 +0000 @@ -194,7 +194,7 @@ modprobe i810fb vram=2 xres=1024 bpp=8 hsync1=30 hsync2=55 vsync1=50 \ vsync2=85 accel=1 mtrr=1 -Or just add the following to /etc/modules.conf +Or just add the following to /etc/modprobe.conf options i810fb vram=2 xres=1024 bpp=16 hsync1=30 hsync2=55 vsync1=50 \ vsync2=85 accel=1 mtrr=1 --- diff/Documentation/filesystems/proc.txt 2003-09-17 12:28:01.000000000 +0100 +++ source/Documentation/filesystems/proc.txt 2004-02-09 10:39:51.000000000 +0000 @@ -900,6 +900,15 @@ Every mounted file system needs a super block, so if you plan to mount lots of file systems, you may want to increase these numbers. +aio-nr and aio-max-nr +--------------------- + +aio-nr is the running total of the number of events specified on the +io_setup system call for all currently active aio contexts. If aio-nr +reaches aio-max-nr then io_setup will fail with EAGAIN. Note that +raising aio-max-nr does not result in the pre-allocation or re-sizing +of any kernel data structures. + 2.2 /proc/sys/fs/binfmt_misc - Miscellaneous binary formats ----------------------------------------------------------- --- diff/Documentation/ftape.txt 2003-10-09 09:47:33.000000000 +0100 +++ source/Documentation/ftape.txt 2004-02-09 10:39:51.000000000 +0000 @@ -242,15 +242,15 @@ Module parameters can be specified either directly when invoking the program 'insmod' at the shell prompt: - insmod ftape.o ft_tracing=4 + modprobe ftape ft_tracing=4 - or by editing the file `/etc/modules.conf' in which case they take + or by editing the file `/etc/modprobe.conf' in which case they take effect each time when the module is loaded with `modprobe' (please refer to the respective manual pages). Thus, you should add a line options ftape ft_tracing=4 - to `/etc/modules.conf` if you intend to increase the debugging + to `/etc/modprobe.conf` if you intend to increase the debugging output of the driver. @@ -298,7 +298,7 @@ 5. Example module parameter setting ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To do the same, but with ftape compiled as a loadable kernel - module, add the following line to `/etc/modules.conf': + module, add the following line to `/etc/modprobe.conf': options ftape ft_probe_fc10=1 ft_tracing=4 --- diff/Documentation/hayes-esp.txt 2002-10-16 04:27:12.000000000 +0100 +++ source/Documentation/hayes-esp.txt 2004-02-09 10:39:51.000000000 +0000 @@ -109,7 +109,7 @@ insmod esp dma=3 trigger=512 The esp module can be automatically loaded when needed. To cause this to -happen, add the following lines to /etc/modules.conf (replacing the last line +happen, add the following lines to /etc/modprobe.conf (replacing the last line with options for your configuration): alias char-major-57 esp --- diff/Documentation/i386/zero-page.txt 2004-02-09 10:36:07.000000000 +0000 +++ source/Documentation/i386/zero-page.txt 2004-02-09 10:39:51.000000000 +0000 @@ -72,8 +72,10 @@ 0x21c unsigned long INITRD_SIZE, size in bytes of ramdisk image 0x220 4 bytes (setup.S) 0x224 unsigned short setup.S heap end pointer +0x2cc 4 bytes DISK80_SIG_BUFFER (setup.S) 0x2d0 - 0x600 E820MAP -0x600 - 0x7D4 EDDBUF (setup.S) +0x600 - 0x7ff EDDBUF (setup.S) for disk signature read sector +0x600 - 0x7d3 EDDBUF (setup.S) for edd data 0x800 string, 2K max COMMAND_LINE, the kernel commandline as copied using CL_OFFSET. --- diff/Documentation/ide.txt 2003-10-27 09:20:36.000000000 +0000 +++ source/Documentation/ide.txt 2004-02-09 10:39:51.000000000 +0000 @@ -198,12 +198,11 @@ can only be compiled into the kernel, and the core code (ide.c) can be compiled as a loadable module provided no chipset support is needed. -When using ide.c/ide-tape.c as modules in combination with kerneld, add: +When using ide.c as a module in combination with kmod, add: alias block-major-3 ide-probe - alias char-major-37 ide-tape -respectively to /etc/modules.conf. +to /etc/modprobe.conf. When ide.c is used as a module, you can pass command line parameters to the driver using the "options=" keyword to insmod, while replacing any ',' with --- diff/Documentation/kernel-parameters.txt 2004-02-09 10:36:07.000000000 +0000 +++ source/Documentation/kernel-parameters.txt 2004-02-09 10:39:51.000000000 +0000 @@ -174,11 +174,18 @@ atascsi= [HW,SCSI] Atari SCSI - atkbd.set= [HW] Select keyboard code set - Format: + atkbd.extra= [HW] Enable extra LEDs and keys on IBM RapidAccess, EzKey + and similar keyboards + + atkbd.reset= [HW] Reset keyboard during initialization + + atkbd.set= [HW] Select keyboard code set + Format: (2 = AT (default) 3 = PS/2) + + atkbd.scroll= [HW] Enable scroll wheel on MS Office and similar keyboards + atkbd.softrepeat= [HW] Use software keyboard repeat - atkbd.reset= [HW] Reset keyboard during initialization autotest [IA64] @@ -237,7 +244,7 @@ Forces specified timesource (if avaliable) to be used when calculating gettimeofday(). If specicified timesource is not avalible, it defaults to PIT. - Format: { pit | tsc | cyclone | ... } + Format: { pit | tsc | cyclone | pmtmr } hpet= [IA-32,HPET] option to disable HPET and use PIT. Format: disable --- diff/Documentation/networking/baycom.txt 2002-10-16 04:28:34.000000000 +0100 +++ source/Documentation/networking/baycom.txt 2004-02-09 10:39:51.000000000 +0000 @@ -93,10 +93,10 @@ modems it should access at which ports. This can be done with the setbaycom utility. If you are only using one modem, you can also configure the driver from the insmod command line (or by means of an option line in -/etc/modules.conf). +/etc/modprobe.conf). Examples: - insmod baycom_ser_fdx mode="ser12*" iobase=0x3f8 irq=4 + modprobe baycom_ser_fdx mode="ser12*" iobase=0x3f8 irq=4 sethdlc -i bcsf0 -p mode "ser12*" io 0x3f8 irq 4 Both lines configure the first port to drive a ser12 modem at the first --- diff/Documentation/networking/bonding.txt 2003-09-30 15:46:10.000000000 +0100 +++ source/Documentation/networking/bonding.txt 2004-02-09 10:39:51.000000000 +0000 @@ -21,7 +21,7 @@ Table of Contents ================= - + Installation Bond Configuration Module Parameters @@ -66,18 +66,18 @@ /usr/include/linux. To install ifenslave.c, do: - # gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave + # gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave # cp ifenslave /sbin/ifenslave Bond Configuration ================== -You will need to add at least the following line to /etc/modules.conf -so the bonding driver will automatically load when the bond0 interface is -configured. Refer to the modules.conf manual page for specific modules.conf -syntax details. The Module Parameters section of this document describes each -bonding driver parameter. +You will need to add at least the following line to /etc/modprobe.conf +so the bonding driver will automatically load when the bond0 interface is +configured. Refer to the modprobe.conf manual page for specific modprobe.conf +syntax details. The Module Parameters section of this document describes each +bonding driver parameter. alias bond0 bonding @@ -113,7 +113,7 @@ network interface be a slave of bond1. Restart the networking subsystem or just bring up the bonding device if your -administration tools allow it. Otherwise, reboot. On Red Hat distros you can +administration tools allow it. Otherwise, reboot. On Red Hat distros you can issue `ifup bond0' or `/etc/rc.d/init.d/network restart'. If the administration tools of your distribution do not support @@ -128,30 +128,30 @@ (use appropriate values for your network above) -You can then create a script containing these commands and place it in the +You can then create a script containing these commands and place it in the appropriate rc directory. If you specifically need all network drivers loaded before the bonding driver, -adding the following line to modules.conf will cause the network driver for +adding the following line to modprobe.conf will cause the network driver for eth0 and eth1 to be loaded before the bonding driver. -probeall bond0 eth0 eth1 bonding +install bond0 /sbin/modprobe -a eth0 eth1 && /sbin/modprobe bonding -Be careful not to reference bond0 itself at the end of the line, or modprobe +Be careful not to reference bond0 itself at the end of the line, or modprobe will die in an endless recursive loop. -To have device characteristics (such as MTU size) propagate to slave devices, -set the bond characteristics before enslaving the device. The characteristics +To have device characteristics (such as MTU size) propagate to slave devices, +set the bond characteristics before enslaving the device. The characteristics are propagated during the enslave process. -If running SNMP agents, the bonding driver should be loaded before any network -drivers participating in a bond. This requirement is due to the the interface -index (ipAdEntIfIndex) being associated to the first interface found with a -given IP address. That is, there is only one ipAdEntIfIndex for each IP -address. For example, if eth0 and eth1 are slaves of bond0 and the driver for -eth0 is loaded before the bonding driver, the interface for the IP address -will be associated with the eth0 interface. This configuration is shown below, -the IP address 192.168.1.1 has an interface index of 2 which indexes to eth0 +If running SNMP agents, the bonding driver should be loaded before any network +drivers participating in a bond. This requirement is due to the the interface +index (ipAdEntIfIndex) being associated to the first interface found with a +given IP address. That is, there is only one ipAdEntIfIndex for each IP +address. For example, if eth0 and eth1 are slaves of bond0 and the driver for +eth0 is loaded before the bonding driver, the interface for the IP address +will be associated with the eth0 interface. This configuration is shown below, +the IP address 192.168.1.1 has an interface index of 2 which indexes to eth0 in the ifDescr table (ifDescr.2). interfaces.ifTable.ifEntry.ifDescr.1 = lo @@ -189,10 +189,10 @@ Module Parameters ================= -Optional parameters for the bonding driver can be supplied as command line -arguments to the insmod command. Typically, these parameters are specified in -the file /etc/modules.conf (see the manual page for modules.conf). The -available bonding driver parameters are listed below. If a parameter is not +Optional parameters for the bonding driver can be supplied as command line +arguments to the insmod command. Typically, these parameters are specified in +the file /etc/modprobe.conf (see the manual page for modprobe.conf). The +available bonding driver parameters are listed below. If a parameter is not specified the default value is used. When initially configuring a bond, it is recommended "tail -f /var/log/messages" be run in a separate window to watch for bonding driver error messages. @@ -202,19 +202,19 @@ during link failures. arp_interval - - Specifies the ARP monitoring frequency in milli-seconds. - If ARP monitoring is used in a load-balancing mode (mode 0 or 2), the - switch should be configured in a mode that evenly distributes packets - across all links - such as round-robin. If the switch is configured to - distribute the packets in an XOR fashion, all replies from the ARP - targets will be received on the same link which could cause the other + + Specifies the ARP monitoring frequency in milli-seconds. + If ARP monitoring is used in a load-balancing mode (mode 0 or 2), the + switch should be configured in a mode that evenly distributes packets + across all links - such as round-robin. If the switch is configured to + distribute the packets in an XOR fashion, all replies from the ARP + targets will be received on the same link which could cause the other team members to fail. ARP monitoring should not be used in conjunction - with miimon. A value of 0 disables ARP monitoring. The default value + with miimon. A value of 0 disables ARP monitoring. The default value is 0. - + arp_ip_target - + Specifies the ip addresses to use when arp_interval is > 0. These are the targets of the ARP request sent to determine the health of the link to the targets. Specify these values in ddd.ddd.ddd.ddd @@ -223,8 +223,8 @@ maximum number of targets that can be specified is set at 16. downdelay - - Specifies the delay time in milli-seconds to disable a link after a + + Specifies the delay time in milli-seconds to disable a link after a link failure has been detected. This should be a multiple of miimon value, otherwise the value will be rounded. The default value is 0. @@ -247,7 +247,7 @@ and bond2 will be created. The default value is 1. miimon - + Specifies the frequency in milli-seconds that MII link monitoring will occur. A value of zero disables MII link monitoring. A value of 100 is a good starting point. See High Availability section for @@ -258,7 +258,7 @@ Specifies one of the bonding policies. The default is round-robin (balance-rr). Possible values are (you can use either the text or numeric option): - + balance-rr or 0 Round-robin policy: Transmit in a sequential order @@ -273,7 +273,7 @@ externally visible on only one port (network adapter) to avoid confusing the switch. This mode provides fault tolerance. - + balance-xor or 2 XOR policy: Transmit based on [(source MAC address @@ -293,7 +293,7 @@ groups that share the same speed and duplex settings. Transmits and receives on all slaves in the active aggregator. - + Pre-requisites: 1. Ethtool support in the base drivers for retrieving the @@ -317,7 +317,7 @@ Ethtool support in the base drivers for retrieving the speed of each slave. - balance-alb or 6 + balance-alb or 6 Adaptive load balancing: includes balance-tlb + receive load balancing (rlb) for IPV4 traffic and does not require @@ -327,7 +327,7 @@ overwrites the src hw address with the unique hw address of one of the slaves in the bond such that different clients use different hw addresses for the server. - + Receive traffic from connections created by the server is also balanced. When the server sends an ARP Request the bonding driver copies and saves the client's IP information @@ -363,25 +363,11 @@ 2. Base driver support for setting the hw address of a device also when it is open. This is required so that there will always be one slave in the team using the bond hw - address (the current_slave) while having a unique hw - address for each slave in the bond. If the current_slave - fails it's hw address is swapped with the new current_slave + address (the curr_active_slave) while having a unique hw + address for each slave in the bond. If the curr_active_slave + fails it's hw address is swapped with the new curr_active_slave that was chosen. -multicast - - Option specifying the mode of operation for multicast support. - Possible values are: - - disabled or 0 - Disabled (no multicast support) - - active or 1 - Enabled on active slave only, useful in active-backup mode - - all or 2 - Enabled on all slaves, this is the default - primary A string (eth0, eth2, etc) to equate to a primary device. If this @@ -397,11 +383,11 @@ primary is only valid in active-backup mode. updelay - - Specifies the delay time in milli-seconds to enable a link after a + + Specifies the delay time in milli-seconds to enable a link after a link up status has been detected. This should be a multiple of miimon value, otherwise the value will be rounded. The default value is 0. - + use_carrier Specifies whether or not miimon should use MII or ETHTOOL @@ -529,20 +515,20 @@ ---------------------------- The bonding driver information files reside in the /proc/net/bonding directory. -Sample contents of /proc/net/bonding/bond0 after the driver is loaded with +Sample contents of /proc/net/bonding/bond0 after the driver is loaded with parameters of mode=0 and miimon=1000 is shown below. - + Bonding Mode: load balancing (round-robin) Currently Active Slave: eth0 MII Status: up MII Polling Interval (ms): 1000 Up Delay (ms): 0 Down Delay (ms): 0 - + Slave Interface: eth1 MII Status: up Link Failure Count: 1 - + Slave Interface: eth0 MII Status: up Link Failure Count: 1 @@ -550,34 +536,34 @@ 2) Network verification ----------------------- The network configuration can be verified using the ifconfig command. In -the example below, the bond0 interface is the master (MASTER) while eth0 and -eth1 are slaves (SLAVE). Notice all slaves of bond0 have the same MAC address +the example below, the bond0 interface is the master (MASTER) while eth0 and +eth1 are slaves (SLAVE). Notice all slaves of bond0 have the same MAC address (HWaddr) as bond0 for all modes except TLB and ALB that require a unique MAC address for each slave. [root]# /sbin/ifconfig -bond0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +bond0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING MASTER MULTICAST MTU:1500 Metric:1 RX packets:7224794 errors:0 dropped:0 overruns:0 frame:0 TX packets:3286647 errors:1 dropped:0 overruns:1 carrier:0 - collisions:0 txqueuelen:0 + collisions:0 txqueuelen:0 -eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 RX packets:3573025 errors:0 dropped:0 overruns:0 frame:0 TX packets:1643167 errors:1 dropped:0 overruns:1 carrier:0 - collisions:0 txqueuelen:100 - Interrupt:10 Base address:0x1080 + collisions:0 txqueuelen:100 + Interrupt:10 Base address:0x1080 -eth1 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +eth1 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 RX packets:3651769 errors:0 dropped:0 overruns:0 frame:0 TX packets:1643480 errors:0 dropped:0 overruns:0 carrier:0 - collisions:0 txqueuelen:100 - Interrupt:9 Base address:0x1400 + collisions:0 txqueuelen:100 + Interrupt:9 Base address:0x1400 Frequently Asked Questions @@ -605,9 +591,9 @@ 5. What happens when a slave link dies? - If your ethernet cards support MII or ETHTOOL link status monitoring - and the MII monitoring has been enabled in the driver (see description - of module parameters), there will be no adverse consequences. This + If your ethernet cards support MII or ETHTOOL link status monitoring + and the MII monitoring has been enabled in the driver (see description + of module parameters), there will be no adverse consequences. This release of the bonding driver knows how to get the MII information and enables or disables its slaves according to their link status. See section on High Availability for additional information. @@ -622,8 +608,8 @@ slave. If neither mii_monitor and arp_interval is configured, the bonding - driver will not handle this situation very well. The driver will - continue to send packets but some packets will be lost. Retransmits + driver will not handle this situation very well. The driver will + continue to send packets but some packets will be lost. Retransmits will cause serious degradation of performance (in the case when one of two slave links fails, 50% packets will be lost, which is a serious problem for both TCP and UDP). @@ -636,9 +622,9 @@ 7. Which switches/systems does it work with? - In round-robin and XOR mode, it works with systems that support + In round-robin and XOR mode, it works with systems that support trunking: - + * Many Cisco switches and routers (look for EtherChannel support). * SunTrunking software. * Alteon AceDirector switches / WebOS (use Trunks). @@ -646,7 +632,7 @@ models (450) can define trunks between ports on different physical units. * Linux bonding, of course ! - + In 802.3ad mode, it works with with systems that support IEEE 802.3ad Dynamic Link Aggregation: @@ -667,21 +653,21 @@ is then passed to all following slaves and remains persistent (even if the the first slave is removed) until the bonding device is brought down or reconfigured. - + If you wish to change the MAC address, you can set it with ifconfig: # ifconfig bond0 hw ether 00:11:22:33:44:55 The MAC address can be also changed by bringing down/up the device and then changing its slaves (or their order): - + # ifconfig bond0 down ; modprobe -r bonding # ifconfig bond0 .... up # ifenslave bond0 eth... This method will automatically take the address from the next slave that will be added. - + To restore your slaves' MAC addresses, you need to detach them from the bond (`ifenslave -d bond0 eth0'), set them down (`ifconfig eth0 down'), unload the drivers (`rmmod 3c59x', for @@ -729,39 +715,38 @@ ================= To implement high availability using the bonding driver, the driver needs to be -compiled as a module, because currently it is the only way to pass parameters +compiled as a module, because currently it is the only way to pass parameters to the driver. This may change in the future. -High availability is achieved by using MII or ETHTOOL status reporting. You -need to verify that all your interfaces support MII or ETHTOOL link status -reporting. On Linux kernel 2.2.17, all the 100 Mbps capable drivers and -yellowfin gigabit driver support MII. To determine if ETHTOOL link reporting -is available for interface eth0, type "ethtool eth0" and the "Link detected:" -line should contain the correct link status. If your system has an interface -that does not support MII or ETHTOOL status reporting, a failure of its link -will not be detected! A message indicating MII and ETHTOOL is not supported by -a network driver is logged when the bonding driver is loaded with a non-zero +High availability is achieved by using MII or ETHTOOL status reporting. You +need to verify that all your interfaces support MII or ETHTOOL link status +reporting. On Linux kernel 2.2.17, all the 100 Mbps capable drivers and +yellowfin gigabit driver support MII. To determine if ETHTOOL link reporting +is available for interface eth0, type "ethtool eth0" and the "Link detected:" +line should contain the correct link status. If your system has an interface +that does not support MII or ETHTOOL status reporting, a failure of its link +will not be detected! A message indicating MII and ETHTOOL is not supported by +a network driver is logged when the bonding driver is loaded with a non-zero miimon value. The bonding driver can regularly check all its slaves links using the ETHTOOL -IOCTL (ETHTOOL_GLINK command) or by checking the MII status registers. The -check interval is specified by the module argument "miimon" (MII monitoring). -It takes an integer that represents the checking time in milliseconds. It -should not come to close to (1000/HZ) (10 milli-seconds on i386) because it -may then reduce the system interactivity. A value of 100 seems to be a good -starting point. It means that a dead link will be detected at most 100 +IOCTL (ETHTOOL_GLINK command) or by checking the MII status registers. The +check interval is specified by the module argument "miimon" (MII monitoring). +It takes an integer that represents the checking time in milliseconds. It +should not come to close to (1000/HZ) (10 milli-seconds on i386) because it +may then reduce the system interactivity. A value of 100 seems to be a good +starting point. It means that a dead link will be detected at most 100 milli-seconds after it goes down. Example: # modprobe bonding miimon=100 -Or, put the following lines in /etc/modules.conf: +Or, put the following line in /etc/modprobe.conf: - alias bond0 bonding options bond0 miimon=100 -There are currently two policies for high availability. They are dependent on +There are currently two policies for high availability. They are dependent on whether: a) hosts are connected to a single host or switch that support trunking @@ -811,7 +796,7 @@ # ifenslave bond0 eth0 eth1 -2) High Availability on two or more switches (or a single switch without +2) High Availability on two or more switches (or a single switch without trunking support) --------------------------------------------------------------------------- This mode is more problematic because it relies on the fact that there @@ -829,9 +814,8 @@ # modprobe bonding miimon=100 mode=1 -Or, put in your /etc/modules.conf : +Or, put in your /etc/modprobe.conf : - alias bond0 bonding options bond0 miimon=100 mode=active-backup Example 1: Using multiple host and multiple switches to build a "no single @@ -870,10 +854,10 @@ connected to one switch and host2's to the other. Such system will survive a failure of a single host, cable, or switch. The worst thing that may happen in the case of a switch failure is that half of the hosts will be temporarily -unreachable until the other switch expires its tables. +unreachable until the other switch expires its tables. Example 2: Using multiple ethernet cards connected to a switch to configure - NIC failover (switch is not required to support trunking). + NIC failover (switch is not required to support trunking). +----------+ +----------+ @@ -933,7 +917,6 @@ must add the promisc flag there; it will be propagated down to the slave interfaces at ifenslave time; a full example might look like: - grep bond0 /etc/modules.conf || echo alias bond0 bonding >/etc/modules.conf ifconfig bond0 promisc up for if in eth1 eth2 ...;do ifconfig $if up @@ -957,7 +940,7 @@ servers, but may be useful when the front switches send multicast information on their links (e.g. VRRP), or even health-check the servers. Use the arp_interval/arp_ip_target parameters to count incoming/outgoing - frames. + frames. @@ -973,13 +956,12 @@ You will also find a lot of information regarding Ethernet, NWay, MII, etc. at www.scyld.com. -For new versions of the driver, patches for older kernels and the updated -userspace tools, take a look at Willy Tarreau's site : +Patches for 2.2 kernels are at Willy Tarreau's site : - http://wtarreau.free.fr/pub/bonding/ - - http://www-miaif.lip6.fr/willy/pub/bonding/ + - http://www-miaif.lip6.fr/~tarreau/pub/bonding/ To get latest informations about Linux Kernel development, please consult the Linux Kernel Mailing List Archives at : - http://boudicca.tux.org/hypermail/linux-kernel/latest/ + http://www.ussg.iu.edu/hypermail/linux/kernel/ -- END -- --- diff/Documentation/networking/dl2k.txt 2002-10-16 04:28:29.000000000 +0100 +++ source/Documentation/networking/dl2k.txt 2004-02-09 10:39:51.000000000 +0000 @@ -37,15 +37,15 @@ Install linux driver as following command: 1. make all -2. insmod dl2k.o +2. insmod dl2k.ko 3. ifconfig eth0 up 10.xxx.xxx.xxx netmask 255.0.0.0 ^^^^^^^^^^^^^^^\ ^^^^^^^^\ IP NETMASK Now eth0 should active, you can test it by "ping" or get more information by "ifconfig". If tested ok, continue the next step. -4. cp dl2k.o /lib/modules/`uname -r`/kernel/drivers/net -5. Add the following lines to /etc/modules.conf: +4. cp dl2k.ko /lib/modules/`uname -r`/kernel/drivers/net +5. Add the following line to /etc/modprobe.conf: alias eth0 dl2k 6. Run "netconfig" or "netconf" to create configuration script ifcfg-eth0 located at /etc/sysconfig/network-scripts or create it manually. @@ -154,8 +154,8 @@ ----------------- 1. Copy dl2k.o to the network modules directory, typically /lib/modules/2.x.x-xx/net or /lib/modules/2.x.x/kernel/drivers/net. - 2. Locate the boot module configuration file, most commonly modules.conf - or conf.modules in the /etc directory. Add the following lines: + 2. Locate the boot module configuration file, most commonly modprobe.conf + or modules.conf (for 2.4) in the /etc directory. Add the following lines: alias ethx dl2k options dl2k --- diff/Documentation/networking/ifenslave.c 2003-09-30 15:46:10.000000000 +0100 +++ source/Documentation/networking/ifenslave.c 2004-02-09 10:39:51.000000000 +0000 @@ -4,8 +4,6 @@ * This program controls the Linux implementation of running multiple * network interfaces in parallel. * - * Usage: ifenslave [-v] master-interface < slave-interface [metric ] > ... - * * Author: Donald Becker * Copyright 1994-1996 Donald Becker * @@ -90,24 +88,30 @@ * - For opt_c: slave should not be set to the master's setting * while it is running. It was already set during enslave. To * simplify things, it is now handeled separately. + * + * - 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes + * set version to 1.1.0 */ -#define APP_VERSION "1.0.12" -#define APP_RELDATE "June 30, 2003" +#define APP_VERSION "1.1.0" +#define APP_RELDATE "December 1, 2003" #define APP_NAME "ifenslave" static char *version = -APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ") " "\nDonald Becker (becker@cesdis.gsfc.nasa.gov).\n" -"detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" -"2.4 kernel support added on 2001/02/16 by Chad N. Tindel (ctindel at ieee dot org.\n"; +APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ")\n" +"o Donald Becker (becker@cesdis.gsfc.nasa.gov).\n" +"o Detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" +"o 2.4 kernel support added on 2001/02/16 by Chad N. Tindel\n" +" (ctindel at ieee dot org).\n"; static const char *usage_msg = -"Usage: ifenslave [-adfrvVh] < [metric ] > ...\n" -" ifenslave -c master-interface slave-if\n"; +"Usage: ifenslave [-f] [...]\n" +" ifenslave -d [...]\n" +" ifenslave -c \n" +" ifenslave --help\n"; -static const char *howto_msg = -"Usage: ifenslave [-adfrvVh] < [metric ] > ...\n" -" ifenslave -c master-interface slave-if\n" +static const char *help_msg = "\n" " To create a bond device, simply follow these three steps :\n" " - ensure that the required drivers are properly loaded :\n" @@ -115,18 +119,32 @@ " - assign an IP address to the bond device :\n" " # ifconfig bond0 netmask broadcast \n" " - attach all the interfaces you need to the bond device :\n" -" # ifenslave bond0 eth0 eth1 eth2\n" +" # ifenslave [{-f|--force}] bond0 eth0 [eth1 [eth2]...]\n" " If bond0 didn't have a MAC address, it will take eth0's. Then, all\n" " interfaces attached AFTER this assignment will get the same MAC addr.\n" -"\n" -" To detach a dead interface without setting the bond device down :\n" -" # ifenslave -d bond0 eth1\n" +" (except for ALB/TLB modes)\n" "\n" " To set the bond device down and automatically release all the slaves :\n" " # ifconfig bond0 down\n" "\n" +" To detach a dead interface without setting the bond device down :\n" +" # ifenslave {-d|--detach} bond0 eth0 [eth1 [eth2]...]\n" +"\n" " To change active slave :\n" -" # ifenslave -c bond0 eth0\n" +" # ifenslave {-c|--change-active} bond0 eth0\n" +"\n" +" To show master interface info\n" +" # ifenslave bond0\n" +"\n" +" To show all interfaces info\n" +" # ifenslave {-a|--all-interfaces}\n" +"\n" +" To be more verbose\n" +" # ifenslave {-v|--verbose} ...\n" +"\n" +" # ifenslave {-u|--usage} Show usage\n" +" # ifenslave {-V|--version} Show version\n" +" # ifenslave {-h|--help} This message\n" "\n"; #include @@ -153,476 +171,332 @@ #include struct option longopts[] = { - /* { name has_arg *flag val } */ - {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ - {"force", 0, 0, 'f'}, /* Force the operation. */ - {"help", 0, 0, '?'}, /* Give help */ - {"howto", 0, 0, 'h'}, /* Give some more help */ - {"receive-slave", 0, 0, 'r'}, /* Make a receive-only slave. */ - {"verbose", 0, 0, 'v'}, /* Report each action taken. */ - {"version", 0, 0, 'V'}, /* Emit version information. */ - {"detach", 0, 0, 'd'}, /* Detach a slave interface. */ - {"change-active", 0, 0, 'c'}, /* Change the active slave. */ - { 0, 0, 0, 0 } + /* { name has_arg *flag val } */ + {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ + {"change-active", 0, 0, 'c'}, /* Change the active slave. */ + {"detach", 0, 0, 'd'}, /* Detach a slave interface. */ + {"force", 0, 0, 'f'}, /* Force the operation. */ + {"help", 0, 0, 'h'}, /* Give help */ + {"usage", 0, 0, 'u'}, /* Give usage */ + {"verbose", 0, 0, 'v'}, /* Report each action taken. */ + {"version", 0, 0, 'V'}, /* Emit version information. */ + { 0, 0, 0, 0} }; /* Command-line flags. */ unsigned int -opt_a = 0, /* Show-all-interfaces flag. */ -opt_f = 0, /* Force the operation. */ -opt_r = 0, /* Set up a Rx-only slave. */ -opt_d = 0, /* detach a slave interface. */ -opt_c = 0, /* change-active-slave flag. */ -verbose = 0, /* Verbose flag. */ -opt_version = 0, -opt_howto = 0; -int skfd = -1; /* AF_INET socket for ioctl() calls. */ +opt_a = 0, /* Show-all-interfaces flag. */ +opt_c = 0, /* Change-active-slave flag. */ +opt_d = 0, /* Detach a slave interface. */ +opt_f = 0, /* Force the operation. */ +opt_h = 0, /* Help */ +opt_u = 0, /* Usage */ +opt_v = 0, /* Verbose flag. */ +opt_V = 0; /* Version */ + +int skfd = -1; /* AF_INET socket for ioctl() calls.*/ +int abi_ver = 0; /* userland - kernel ABI version */ +int hwaddr_set = 0; /* Master's hwaddr is set */ +int saved_errno; + +struct ifreq master_mtu, master_flags, master_hwaddr; +struct ifreq slave_mtu, slave_flags, slave_hwaddr; + +struct dev_ifr { + struct ifreq *req_ifr; + char *req_name; + int req_type; +}; + +struct dev_ifr master_ifra[] = { + {&master_mtu, "SIOCGIFMTU", SIOCGIFMTU}, + {&master_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS}, + {&master_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR}, + {NULL, "", 0} +}; + +struct dev_ifr slave_ifra[] = { + {&slave_mtu, "SIOCGIFMTU", SIOCGIFMTU}, + {&slave_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS}, + {&slave_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR}, + {NULL, "", 0} +}; static void if_print(char *ifname); -static int get_abi_ver(char *master_ifname); +static int get_drv_info(char *master_ifname); +static int get_if_settings(char *ifname, struct dev_ifr ifra[]); +static int get_slave_flags(char *slave_ifname); +static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr); +static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr); +static int set_slave_mtu(char *slave_ifname, int mtu); +static int set_if_flags(char *ifname, short flags); +static int set_if_up(char *ifname, short flags); +static int set_if_down(char *ifname, short flags); +static int clear_if_addr(char *ifname); +static int set_if_addr(char *master_ifname, char *slave_ifname); +static int change_active(char *master_ifname, char *slave_ifname); +static int enslave(char *master_ifname, char *slave_ifname); +static int release(char *master_ifname, char *slave_ifname); +#define v_print(fmt, args...) \ + if (opt_v) \ + fprintf(stderr, fmt, ## args ) -int -main(int argc, char **argv) +int main(int argc, char *argv[]) { - struct ifreq ifr2, if_hwaddr, if_ipaddr, if_metric, if_mtu, if_dstaddr; - struct ifreq if_netmask, if_brdaddr, if_flags; - int rv, goterr = 0; - int c, errflag = 0; - sa_family_t master_family; char **spp, *master_ifname, *slave_ifname; - int hwaddr_notset; - int abi_ver = 0; + int c, i, rv; + int res = 0; + int exclusive = 0; - while ((c = getopt_long(argc, argv, "acdfrvV?h", longopts, 0)) != EOF) + while ((c = getopt_long(argc, argv, "acdfhuvV", longopts, 0)) != EOF) { switch (c) { - case 'a': opt_a++; break; - case 'f': opt_f++; break; - case 'r': opt_r++; break; - case 'd': opt_d++; break; - case 'c': opt_c++; break; - case 'v': verbose++; break; - case 'V': opt_version++; break; - case 'h': opt_howto++; break; - case '?': errflag++; - } + case 'a': opt_a++; exclusive++; break; + case 'c': opt_c++; exclusive++; break; + case 'd': opt_d++; exclusive++; break; + case 'f': opt_f++; exclusive++; break; + case 'h': opt_h++; exclusive++; break; + case 'u': opt_u++; exclusive++; break; + case 'v': opt_v++; break; + case 'V': opt_V++; exclusive++; break; - /* option check */ - if (opt_c) - if(opt_a || opt_f || opt_r || opt_d || verbose || opt_version || - opt_howto || errflag ) { + case '?': fprintf(stderr, usage_msg); - return 2; + res = 2; + goto out; } + } - if (errflag) { + /* options check */ + if (exclusive > 1) { fprintf(stderr, usage_msg); - return 2; + res = 2; + goto out; } - if (opt_howto) { - fprintf(stderr, howto_msg); - return 0; + if (opt_v || opt_V) { + printf(version); + if (opt_V) { + res = 0; + goto out; + } } - if (verbose || opt_version) { - printf(version); - if (opt_version) - exit(0); + if (opt_u) { + printf(usage_msg); + res = 0; + goto out; } - /* Open a basic socket. */ - if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) { - perror("socket"); - exit(-1); + if (opt_h) { + printf(usage_msg); + printf(help_msg); + res = 0; + goto out; } - if (verbose) - fprintf(stderr, "DEBUG: argc=%d, optind=%d and argv[optind] is %s.\n", - argc, optind, argv[optind]); + /* Open a basic socket */ + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("socket"); + res = 1; + goto out; + } - /* No remaining args means show all interfaces. */ - if (optind == argc) { - if_print((char *)NULL); - (void) close(skfd); - exit(0); + if (opt_a) { + if (optind == argc) { + /* No remaining args */ + /* show all interfaces */ + if_print((char *)NULL); + goto out; + } else { + /* Just show usage */ + fprintf(stderr, usage_msg); + res = 2; + goto out; + } } - /* Copy the interface name. */ + /* Copy the interface name */ spp = argv + optind; master_ifname = *spp++; - slave_ifname = *spp++; - /* Check command line. */ - if (opt_c) { - char **tempp = spp; - if ((master_ifname == NULL)||(slave_ifname == NULL)||(*tempp++ != NULL)) { - fprintf(stderr, usage_msg); - (void) close(skfd); - return 2; - } + if (master_ifname == NULL) { + fprintf(stderr, usage_msg); + res = 2; + goto out; } - /* A single args means show the configuration for this interface. */ - if (slave_ifname == NULL) { - if_print(master_ifname); - (void) close(skfd); - exit(0); + /* exchange abi version with bonding module */ + res = get_drv_info(master_ifname); + if (res) { + fprintf(stderr, + "Master '%s': Error: handshake with driver failed. " + "Aborting\n", + master_ifname); + goto out; } - /* exchange abi version with bonding driver */ - abi_ver = get_abi_ver(master_ifname); - if (abi_ver < 0) { - (void) close(skfd); - exit(1); - } - - /* Get the vitals from the master interface. */ - { - struct ifreq *ifra[7] = { &if_ipaddr, &if_mtu, &if_dstaddr, - &if_brdaddr, &if_netmask, &if_flags, - &if_hwaddr }; - const char *req_name[7] = { - "IP address", "MTU", "destination address", - "broadcast address", "netmask", "status flags", - "hardware address" }; - const int ioctl_req_type[7] = { - SIOCGIFADDR, SIOCGIFMTU, SIOCGIFDSTADDR, - SIOCGIFBRDADDR, SIOCGIFNETMASK, SIOCGIFFLAGS, - SIOCGIFHWADDR }; - int i; - - for (i = 0; i < 7; i++) { - strncpy(ifra[i]->ifr_name, master_ifname, IFNAMSIZ); - if (ioctl(skfd, ioctl_req_type[i], ifra[i]) < 0) { - fprintf(stderr, - "Something broke getting the master's %s: %s.\n", - req_name[i], strerror(errno)); - } - } - - /* check if master is up; if not then fail any operation */ - if (!(if_flags.ifr_flags & IFF_UP)) { - fprintf(stderr, "Illegal operation; the specified master interface '%s' is not up.\n", master_ifname); - (void) close(skfd); - exit (1); - } + slave_ifname = *spp++; - hwaddr_notset = 1; /* assume master's address not set yet */ - for (i = 0; hwaddr_notset && (i < 6); i++) { - hwaddr_notset &= ((unsigned char *)if_hwaddr.ifr_hwaddr.sa_data)[i] == 0; + if (slave_ifname == NULL) { + if (opt_d || opt_c) { + fprintf(stderr, usage_msg); + res = 2; + goto out; } - /* The family '1' is ARPHRD_ETHER for ethernet. */ - if (if_hwaddr.ifr_hwaddr.sa_family != 1 && !opt_f) { - fprintf(stderr, "The specified master interface '%s' is not" - " ethernet-like.\n This program is designed to work" - " with ethernet-like network interfaces.\n" - " Use the '-f' option to force the operation.\n", - master_ifname); - (void) close(skfd); - exit (1); - } - master_family = if_hwaddr.ifr_hwaddr.sa_family; - if (verbose) { - unsigned char *hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data; - printf("The current hardware address (SIOCGIFHWADDR) of %s is type %d " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", master_ifname, - if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], - hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } + /* A single arg means show the + * configuration for this interface + */ + if_print(master_ifname); + goto out; } + res = get_if_settings(master_ifname, master_ifra); + if (res) { + /* Probably a good reason not to go on */ + fprintf(stderr, + "Master '%s': Error: get settings failed: %s. " + "Aborting\n", + master_ifname, strerror(res)); + goto out; + } - /* do this when enslaving interfaces */ - do { - if (opt_d) { /* detach a slave interface from the master */ - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDRELEASE, &if_flags) < 0) && - (ioctl(skfd, BOND_RELEASE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDRELEASE: cannot detach %s from %s. errno=%s.\n", - slave_ifname, master_ifname, strerror(errno)); - } - else if (abi_ver < 1) { - /* The driver is using an old ABI, so we'll set the interface - * down to avoid any conflicts due to same IP/MAC - */ - strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, - strerror(saved_errno)); - } - else { - ifr2.ifr_flags &= ~(IFF_UP | IFF_RUNNING); - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } - } - } - } else if (opt_c) { /* change primary slave */ - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &if_flags) < 0) && - (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDCHANGEACTIVE: %s.\n", strerror(errno)); - } - } else { /* attach a slave interface to the master */ - - strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, - strerror(saved_errno)); - (void) close(skfd); - return 1; - } - - if ((ifr2.ifr_flags & IFF_SLAVE) && !opt_r) { - fprintf(stderr, "%s is already a slave\n", slave_ifname); - (void) close(skfd); - return 1; - } - - /* if hwaddr_notset, assign the slave hw address to the master */ - if (hwaddr_notset) { - /* assign the slave hw address to the - * master since it currently does not - * have one; otherwise, slaves may - * have different hw addresses in - * active-backup mode as seen when enslaving - * using "ifenslave bond0 eth0 eth1" because - * hwaddr_notset is set outside this loop. - * TODO: put this and the "else" portion in - * a function. - */ - /* get the slaves MAC address */ - strncpy(if_hwaddr.ifr_name, slave_ifname, - IFNAMSIZ); - rv = ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr); - if (-1 == rv) { - fprintf(stderr, "Could not get MAC " - "address of %s: %s\n", - slave_ifname, - strerror(errno)); - strncpy(if_hwaddr.ifr_name, - master_ifname, IFNAMSIZ); - goterr = 1; - } - - if (!goterr) { - if (abi_ver < 1) { - /* In ABI versions older than 1, the - * master's set_mac routine couldn't - * work if it was up, because it - * used the default ethernet set_mac - * function. - */ - /* bring master down */ - if_flags.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, - &if_flags) < 0) { - goterr = 1; - fprintf(stderr, - "Shutting down " - "interface %s failed: " - "%s\n", - master_ifname, - strerror(errno)); - } - } - - strncpy(if_hwaddr.ifr_name, - master_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFHWADDR, - &if_hwaddr) < 0) { - fprintf(stderr, - "Could not set MAC " - "address of %s: %s\n", - master_ifname, - strerror(errno)); - goterr=1; - } else { - hwaddr_notset = 0; - } - - if (abi_ver < 1) { - /* bring master back up */ - if_flags.ifr_flags |= IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, - &if_flags) < 0) { - fprintf(stderr, - "Bringing up interface " - "%s failed: %s\n", - master_ifname, - strerror(errno)); - } - } - } - } else if (abi_ver < 1) { /* if (hwaddr_notset) */ - - /* The driver is using an old ABI, so we'll set the interface - * down and assign the master's hwaddr to it - */ - if (ifr2.ifr_flags & IFF_UP) { - ifr2.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } - } - - strncpy(if_hwaddr.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFHWADDR, &if_hwaddr) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCSIFHWADDR on %s failed: %s\n", if_hwaddr.ifr_name, - strerror(saved_errno)); - if (saved_errno == EBUSY) - fprintf(stderr, " The slave device %s is busy: it must be" - " idle before running this command.\n", slave_ifname); - else if (saved_errno == EOPNOTSUPP) - fprintf(stderr, " The slave device you specified does not support" - " setting the MAC address.\n Your kernel likely does not" - " support slave devices.\n"); - else if (saved_errno == EINVAL) - fprintf(stderr, " The slave device's address type does not match" - " the master's address type.\n"); - } else { - if (verbose) { - unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data; - printf("Slave's (%s) hardware address set to " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", slave_ifname, - hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } - } - } + /* check if master is indeed a master; + * if not then fail any operation + */ + if (!(master_flags.ifr_flags & IFF_MASTER)) { + fprintf(stderr, + "Illegal operation; the specified interface '%s' " + "is not a master. Aborting\n", + master_ifname); + res = 1; + goto out; + } - if (*spp && !strcmp(*spp, "metric")) { - if (*++spp == NULL) { - fprintf(stderr, usage_msg); - (void) close(skfd); - exit(2); - } - if_metric.ifr_metric = atoi(*spp); - strncpy(if_metric.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFMETRIC, &if_metric) < 0) { - fprintf(stderr, "SIOCSIFMETRIC on %s: %s\n", slave_ifname, - strerror(errno)); - goterr = 1; - } - spp++; - } + /* check if master is up; if not then fail any operation */ + if (!(master_flags.ifr_flags & IFF_UP)) { + fprintf(stderr, + "Illegal operation; the specified master interface " + "'%s' is not up.\n", + master_ifname); + res = 1; + goto out; + } - if (strncpy(if_ipaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFADDR, &if_ipaddr) < 0) { - fprintf(stderr, - "Something broke setting the slave's address: %s.\n", - strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_ipaddr.ifr_addr.sa_data; - printf("Set the slave's (%s) IP address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } - } + /* Only for enslaving */ + if (!opt_c && !opt_d) { + sa_family_t master_family = master_hwaddr.ifr_hwaddr.sa_family; + unsigned char *hwaddr = + (unsigned char *)master_hwaddr.ifr_hwaddr.sa_data; - if (strncpy(if_mtu.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFMTU, &if_mtu) < 0) { - fprintf(stderr, "Something broke setting the slave MTU: %s.\n", - strerror(errno)); - } else { - if (verbose) - printf("Set the slave's (%s) MTU to %d.\n", slave_ifname, if_mtu.ifr_mtu); - } + /* The family '1' is ARPHRD_ETHER for ethernet. */ + if (master_family != 1 && !opt_f) { + fprintf(stderr, + "Illegal operation: The specified master " + "interface '%s' is not ethernet-like.\n " + "This program is designed to work with " + "ethernet-like network interfaces.\n " + "Use the '-f' option to force the " + "operation.\n", + master_ifname); + res = 1; + goto out; + } - if (strncpy(if_dstaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFDSTADDR, &if_dstaddr) < 0) { - fprintf(stderr, "Error setting the slave (%s) with SIOCSIFDSTADDR: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_dstaddr.ifr_dstaddr.sa_data; - printf("Set the slave's (%s) destination address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } + /* Check master's hw addr */ + for (i = 0; i < 6; i++) { + if (hwaddr[i] != 0) { + hwaddr_set = 1; + break; } + } - if (strncpy(if_brdaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFBRDADDR, &if_brdaddr) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) broadcast address: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_brdaddr.ifr_broadaddr.sa_data; - printf("Set the slave's (%s) broadcast address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } - } + if (hwaddr_set) { + v_print("current hardware address of master '%s' " + "is %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " + "type %d\n", + master_ifname, + hwaddr[0], hwaddr[1], + hwaddr[2], hwaddr[3], + hwaddr[4], hwaddr[5], + master_family); + } + } - if (strncpy(if_netmask.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFNETMASK, &if_netmask) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) netmask: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_netmask.ifr_netmask.sa_data; - printf("Set the slave's (%s) netmask to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + /* Accepts only one slave */ + if (opt_c) { + /* change active slave */ + res = get_slave_flags(slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: get flags failed. " + "Aborting\n", + slave_ifname); + goto out; + } + res = change_active(master_ifname, slave_ifname); + if (res) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Change active failed\n", + master_ifname, slave_ifname); + } + } else { + /* Accept multiple slaves */ + do { + if (opt_d) { + /* detach a slave interface from the master */ + rv = get_slave_flags(slave_ifname); + if (rv) { + /* Can't work with this slave. */ + /* remember the error and skip it*/ + fprintf(stderr, + "Slave '%s': Error: get flags " + "failed. Skipping\n", + slave_ifname); + res = rv; + continue; } - } - - if (abi_ver < 1) { - - /* The driver is using an old ABI, so we'll set the interface - * up before enslaving it - */ - ifr2.ifr_flags |= IFF_UP; - if ((ifr2.ifr_flags &= ~(IFF_SLAVE | IFF_MASTER)) == 0 - || strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) flags: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) - printf("Set the slave's (%s) flags %4.4x.\n", - slave_ifname, if_flags.ifr_flags); + rv = release(master_ifname, slave_ifname); + if (rv) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Release failed\n", + master_ifname, slave_ifname); + res = rv; } } else { - /* the bonding module takes care of setting the slave's mac address - * and opening its interface - */ - if (ifr2.ifr_flags & IFF_UP) { /* the interface will need to be down */ - ifr2.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } + /* attach a slave interface to the master */ + rv = get_if_settings(slave_ifname, slave_ifra); + if (rv) { + /* Can't work with this slave. */ + /* remember the error and skip it*/ + fprintf(stderr, + "Slave '%s': Error: get " + "settings failed: %s. " + "Skipping\n", + slave_ifname, strerror(rv)); + res = rv; + continue; } - } - - /* Do the real thing */ - if (!opt_r) { - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDENSLAVE, &if_flags) < 0) && - (ioctl(skfd, BOND_ENSLAVE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDENSLAVE: %s.\n", strerror(errno)); + rv = enslave(master_ifname, slave_ifname); + if (rv) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Enslave failed\n", + master_ifname, slave_ifname); + res = rv; } } - } - } while ( (slave_ifname = *spp++) != NULL); + } while ((slave_ifname = *spp++) != NULL); + } - /* Close the socket. */ - (void) close(skfd); +out: + if (skfd >= 0) { + close(skfd); + } - return(goterr); + return res; } static short mif_flags; @@ -631,35 +505,34 @@ static int if_getconfig(char *ifname) { struct ifreq ifr; - int metric, mtu; /* Parameters of the master interface. */ + int metric, mtu; /* Parameters of the master interface. */ struct sockaddr dstaddr, broadaddr, netmask; + unsigned char *hwaddr; strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) return -1; mif_flags = ifr.ifr_flags; printf("The result of SIOCGIFFLAGS on %s is %x.\n", - ifname, ifr.ifr_flags); + ifname, ifr.ifr_flags); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0) return -1; printf("The result of SIOCGIFADDR is %2.2x.%2.2x.%2.2x.%2.2x.\n", - ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1], - ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]); + ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1], + ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) return -1; - { - /* Gotta convert from 'char' to unsigned for printf(). */ - unsigned char *hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; - printf("The result of SIOCGIFHWADDR is type %d " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", - ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], - hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } + /* Gotta convert from 'char' to unsigned for printf(). */ + hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; + printf("The result of SIOCGIFHWADDR is type %d " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], + hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) { @@ -691,7 +564,7 @@ } else netmask = ifr.ifr_netmask; - return(0); + return 0; } static void if_print(char *ifname) @@ -705,15 +578,16 @@ ifc.ifc_len = sizeof(buff); ifc.ifc_buf = buff; if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { - fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); + perror("SIOCGIFCONF failed"); return; } ifr = ifc.ifc_req; for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { if (if_getconfig(ifr->ifr_name) < 0) { - fprintf(stderr, "%s: unknown interface.\n", - ifr->ifr_name); + fprintf(stderr, + "%s: unknown interface.\n", + ifr->ifr_name); continue; } @@ -721,16 +595,18 @@ /*ife_print(&ife);*/ } } else { - if (if_getconfig(ifname) < 0) - fprintf(stderr, "%s: unknown interface.\n", ifname); + if (if_getconfig(ifname) < 0) { + fprintf(stderr, + "%s: unknown interface.\n", ifname); + } } } -static int get_abi_ver(char *master_ifname) +static int get_drv_info(char *master_ifname) { struct ifreq ifr; struct ethtool_drvinfo info; - int abi_ver = 0; + char *endptr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); @@ -739,24 +615,487 @@ info.cmd = ETHTOOL_GDRVINFO; strncpy(info.driver, "ifenslave", 32); snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); - if (ioctl(skfd, SIOCETHTOOL, &ifr) >= 0) { - char *endptr; - abi_ver = strtoul(info.fw_version, &endptr, 0); - if (*endptr) { - fprintf(stderr, "Error: got invalid string as an ABI " - "version from the bonding module\n"); - return -1; + if (ioctl(skfd, SIOCETHTOOL, &ifr) < 0) { + if (errno == EOPNOTSUPP) { + goto out; } + + saved_errno = errno; + v_print("Master '%s': Error: get bonding info failed %s\n", + master_ifname, strerror(saved_errno)); + return 1; } - if (verbose) { - printf("ABI ver is %d\n", abi_ver); + abi_ver = strtoul(info.fw_version, &endptr, 0); + if (*endptr) { + v_print("Master '%s': Error: got invalid string as an ABI " + "version from the bonding module\n", + master_ifname); + return 1; } - return abi_ver; + +out: + v_print("ABI ver is %d\n", abi_ver); + + return 0; } +static int change_active(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + if (!(slave_flags.ifr_flags & IFF_SLAVE)) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is not a slave\n", + slave_ifname); + return 1; + } + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &ifr) < 0) && + (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDCHANGEACTIVE failed: " + "%s\n", + master_ifname, strerror(saved_errno)); + res = 1; + } + + return res; +} + +static int enslave(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + + if (slave_flags.ifr_flags & IFF_SLAVE) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is already a slave\n", + slave_ifname); + return 1; + } + + res = set_if_down(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface down failed\n", + slave_ifname); + return res; + } + + if (abi_ver < 2) { + /* Older bonding versions would panic if the slave has no IP + * address, so get the IP setting from the master. + */ + res = set_if_addr(master_ifname, slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set address failed\n", + slave_ifname); + return res; + } + } else { + res = clear_if_addr(slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: clear address failed\n", + slave_ifname); + return res; + } + } + + if (master_mtu.ifr_mtu != slave_mtu.ifr_mtu) { + res = set_slave_mtu(slave_ifname, master_mtu.ifr_mtu); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set MTU failed\n", + slave_ifname); + return res; + } + } + + if (hwaddr_set) { + /* Master already has an hwaddr + * so set it's hwaddr to the slave + */ + if (abi_ver < 1) { + /* The driver is using an old ABI, so + * the application sets the slave's + * hwaddr + */ + res = set_slave_hwaddr(slave_ifname, + &(master_hwaddr.ifr_hwaddr)); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set hw address " + "failed\n", + slave_ifname); + goto undo_mtu; + } + + /* For old ABI the application needs to bring the + * slave back up + */ + res = set_if_up(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface " + "down failed\n", + slave_ifname); + goto undo_slave_mac; + } + } + /* The driver is using a new ABI, + * so the driver takes care of setting + * the slave's hwaddr and bringing + * it up again + */ + } else { + /* No hwaddr for master yet, so + * set the slave's hwaddr to it + */ + if (abi_ver < 1) { + /* For old ABI, the master needs to be + * down before setting it's hwaddr + */ + res = set_if_down(master_ifname, master_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Master '%s': Error: bring interface " + "down failed\n", + master_ifname); + goto undo_mtu; + } + } + + res = set_master_hwaddr(master_ifname, + &(slave_hwaddr.ifr_hwaddr)); + if (res) { + fprintf(stderr, + "Master '%s': Error: set hw address " + "failed\n", + master_ifname); + goto undo_mtu; + } + + if (abi_ver < 1) { + /* For old ABI, bring the master + * back up + */ + res = set_if_up(master_ifname, master_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Master '%s': Error: bring interface " + "up failed\n", + master_ifname); + goto undo_master_mac; + } + } + + hwaddr_set = 1; + } + + /* Do the real thing */ + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDENSLAVE, &ifr) < 0) && + (ioctl(skfd, BOND_ENSLAVE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDENSLAVE failed: %s\n", + master_ifname, strerror(saved_errno)); + res = 1; + } + + if (res) { + goto undo_master_mac; + } + + return 0; + +/* rollback (best effort) */ +undo_master_mac: + set_master_hwaddr(master_ifname, &(master_hwaddr.ifr_hwaddr)); + hwaddr_set = 0; + goto undo_mtu; +undo_slave_mac: + set_slave_hwaddr(slave_ifname, &(slave_hwaddr.ifr_hwaddr)); +undo_mtu: + set_slave_mtu(slave_ifname, slave_mtu.ifr_mtu); + return res; +} + +static int release(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + + if (!(slave_flags.ifr_flags & IFF_SLAVE)) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is not a slave\n", + slave_ifname); + return 1; + } + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDRELEASE, &ifr) < 0) && + (ioctl(skfd, BOND_RELEASE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDRELEASE failed: %s\n", + master_ifname, strerror(saved_errno)); + return 1; + } else if (abi_ver < 1) { + /* The driver is using an old ABI, so we'll set the interface + * down to avoid any conflicts due to same MAC/IP + */ + res = set_if_down(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface " + "down failed\n", + slave_ifname); + } + } + + /* set to default mtu */ + set_slave_mtu(slave_ifname, 1500); + + return res; +} + +static int get_if_settings(char *ifname, struct dev_ifr ifra[]) +{ + int i; + int res = 0; + + for (i = 0; ifra[i].req_ifr; i++) { + strncpy(ifra[i].req_ifr->ifr_name, ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].req_type, ifra[i].req_ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: %s failed: %s\n", + ifname, ifra[i].req_name, + strerror(saved_errno)); + + return saved_errno; + } + } + + return 0; +} + +static int get_slave_flags(char *slave_ifname) +{ + int res = 0; + + strncpy(slave_flags.ifr_name, slave_ifname, IFNAMSIZ); + res = ioctl(skfd, SIOCGIFFLAGS, &slave_flags); + if (res < 0) { + saved_errno = errno; + v_print("Slave '%s': Error: SIOCGIFFLAGS failed: %s\n", + slave_ifname, strerror(saved_errno)); + } else { + v_print("Slave %s: flags %04X.\n", + slave_ifname, slave_flags.ifr_flags); + } + + return res; +} + +static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr) +{ + unsigned char *addr = (unsigned char *)hwaddr->sa_data; + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); + res = ioctl(skfd, SIOCSIFHWADDR, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCSIFHWADDR failed: %s\n", + master_ifname, strerror(saved_errno)); + return res; + } else { + v_print("Master '%s': hardware address set to " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + master_ifname, addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); + } + + return res; +} + +static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr) +{ + unsigned char *addr = (unsigned char *)hwaddr->sa_data; + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); + res = ioctl(skfd, SIOCSIFHWADDR, &ifr); + if (res < 0) { + saved_errno = errno; + + v_print("Slave '%s': Error: SIOCSIFHWADDR failed: %s\n", + slave_ifname, strerror(saved_errno)); + + if (saved_errno == EBUSY) { + v_print(" The device is busy: it must be idle " + "before running this command.\n"); + } else if (saved_errno == EOPNOTSUPP) { + v_print(" The device does not support setting " + "the MAC address.\n" + " Your kernel likely does not support slave " + "devices.\n"); + } else if (saved_errno == EINVAL) { + v_print(" The device's address type does not match " + "the master's address type.\n"); + } + return res; + } else { + v_print("Slave '%s': hardware address set to " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + slave_ifname, addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); + } + + return res; +} + +static int set_slave_mtu(char *slave_ifname, int mtu) +{ + struct ifreq ifr; + int res = 0; + + ifr.ifr_mtu = mtu; + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + + res = ioctl(skfd, SIOCSIFMTU, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Slave '%s': Error: SIOCSIFMTU failed: %s\n", + slave_ifname, strerror(saved_errno)); + } else { + v_print("Slave '%s': MTU set to %d.\n", slave_ifname, mtu); + } + + return res; +} + +static int set_if_flags(char *ifname, short flags) +{ + struct ifreq ifr; + int res = 0; + + ifr.ifr_flags = flags; + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + + res = ioctl(skfd, SIOCSIFFLAGS, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: SIOCSIFFLAGS failed: %s\n", + ifname, strerror(saved_errno)); + } else { + v_print("Interface '%s': flags set to %04X.\n", ifname, flags); + } + + return res; +} + +static int set_if_up(char *ifname, short flags) +{ + return set_if_flags(ifname, flags | IFF_UP); +} + +static int set_if_down(char *ifname, short flags) +{ + return set_if_flags(ifname, flags & ~IFF_UP); +} + +static int clear_if_addr(char *ifname) +{ + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data)); + + res = ioctl(skfd, SIOCSIFADDR, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: SIOCSIFADDR failed: %s\n", + ifname, strerror(saved_errno)); + } else { + v_print("Interface '%s': address cleared\n", ifname); + } + + return res; +} + +static int set_if_addr(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res; + unsigned char *ipaddr; + int i; + struct { + char *req_name; + char *desc; + int g_ioctl; + int s_ioctl; + } ifra[] = { + {"IFADDR", "addr", SIOCGIFADDR, SIOCSIFADDR}, + {"DSTADDR", "destination addr", SIOCGIFDSTADDR, SIOCSIFDSTADDR}, + {"BRDADDR", "broadcast addr", SIOCGIFBRDADDR, SIOCSIFBRDADDR}, + {"NETMASK", "netmask", SIOCGIFNETMASK, SIOCSIFNETMASK}, + {NULL, NULL, 0, 0}, + }; + + for (i = 0; ifra[i].req_name; i++) { + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].g_ioctl, &ifr); + if (res < 0) { + int saved_errno = errno; + + v_print("Interface '%s': Error: SIOCG%s failed: %s\n", + master_ifname, ifra[i].req_name, + strerror(saved_errno)); + + ifr.ifr_addr.sa_family = AF_INET; + memset(ifr.ifr_addr.sa_data, 0, + sizeof(ifr.ifr_addr.sa_data)); + } + + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].s_ioctl, &ifr); + if (res < 0) { + int saved_errno = errno; + + v_print("Interface '%s': Error: SIOCS%s failed: %s\n", + slave_ifname, ifra[i].req_name, + strerror(saved_errno)); + + return res; + } + + ipaddr = ifr.ifr_addr.sa_data; + v_print("Interface '%s': set IP %s to %d.%d.%d.%d\n", + slave_ifname, ifra[i].desc, + ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + } + + return 0; +} /* * Local variables: @@ -768,3 +1107,4 @@ * compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave" * End: */ + --- diff/Documentation/networking/ltpc.txt 2002-10-16 04:27:48.000000000 +0100 +++ source/Documentation/networking/ltpc.txt 2004-02-09 10:39:51.000000000 +0000 @@ -25,7 +25,7 @@ If you load the driver as a module, you can pass the parameters "io=", "irq=", and "dma=" on the command line with insmod or modprobe, or add -them as options in /etc/modules.conf: +them as options in /etc/modprobe.conf: alias lt0 ltpc # autoload the module when the interface is configured options ltpc io=0x240 irq=9 dma=1 --- diff/Documentation/networking/sk98lin.txt 2004-02-09 10:36:07.000000000 +0000 +++ source/Documentation/networking/sk98lin.txt 2004-02-09 10:39:51.000000000 +0000 @@ -174,7 +174,7 @@ 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). +in the file /etc/modprobe.conf (or /etc/modules.conf in 2.4 or earlier). To set the driver parameters in this file, proceed as follows: 1. Insert a line of the form : --- diff/Documentation/networking/tuntap.txt 2003-05-21 11:49:49.000000000 +0100 +++ source/Documentation/networking/tuntap.txt 2004-02-09 10:39:51.000000000 +0000 @@ -45,13 +45,10 @@ bogus network interfaces to trick firewalls or administrators. Driver module autoloading - Make sure that "Kernel module loader" - module auto-loading support is enabled - in your kernel. - Add the following line to the /etc/modules.conf: - alias char-major-10-200 tun - and run - depmod -a + Make sure that "Kernel module loader" - module auto-loading + support is enabled in your kernel. The kernel should load it on + first access. Manual loading insert the module by hand: --- diff/Documentation/networking/vortex.txt 2003-08-20 14:16:23.000000000 +0100 +++ source/Documentation/networking/vortex.txt 2004-02-09 10:39:51.000000000 +0000 @@ -59,8 +59,8 @@ ================= There are several parameters which may be provided to the driver when -its module is loaded. These are usually placed in /etc/modules.conf -(used to be conf.modules). Example: +its module is loaded. These are usually placed in /etc/modprobe.conf +(/etc/modules.conf in 2.4). Example: options 3c59x debug=3 rx_copybreak=300 @@ -413,9 +413,9 @@ 1) Increase the debug level. Usually this is done via: - a) modprobe driver.o debug=7 - b) In /etc/conf.modules (or modules.conf): - options driver_name debug=7 + a) modprobe driver debug=7 + b) In /etc/modprobe.conf (or /etc/modules.conf for 2.4): + options driver debug=7 2) Recreate the problem with the higher debug level, send all logs to the maintainer. --- diff/Documentation/parport.txt 2002-10-16 04:28:25.000000000 +0100 +++ source/Documentation/parport.txt 2004-02-09 10:39:51.000000000 +0000 @@ -39,7 +39,7 @@ KMod ---- -If you use kmod, you will find it useful to edit /etc/modules.conf. +If you use kmod, you will find it useful to edit /etc/modprobe.conf. Here is an example of the lines that need to be added: alias parport_lowlevel parport_pc --- diff/Documentation/rocket.txt 2003-06-30 10:07:18.000000000 +0100 +++ source/Documentation/rocket.txt 2004-02-09 10:39:51.000000000 +0000 @@ -43,7 +43,7 @@ If installed as a module, the module must be loaded. This can be done manually by entering "modprobe rocket". To have the module loaded automatically -upon system boot, edit the /etc/modules.conf file and add the line +upon system boot, edit the /etc/modprobe.conf file and add the line "alias char-major-46 rocket". In order to use the ports, their device names (nodes) must be created with mknod. --- diff/Documentation/s390/3270.txt 2003-08-20 14:16:23.000000000 +0100 +++ source/Documentation/s390/3270.txt 2004-02-09 10:39:51.000000000 +0000 @@ -48,7 +48,7 @@ script and the resulting /tmp/mkdev3270. If you have chosen to make tub3270 a module, you add a line to -/etc/modules.conf. If you are working on a VM virtual machine, you +/etc/modprobe.conf. If you are working on a VM virtual machine, you can use DEF GRAF to define virtual 3270 devices. You may generate both 3270 and 3215 console support, or one or the @@ -60,7 +60,7 @@ In brief, these are the steps: 1. Install the tub3270 patch - 2. (If a module) add a line to /etc/modules.conf + 2. (If a module) add a line to /etc/modprobe.conf 3. (If VM) define devices with DEF GRAF 4. Reboot 5. Configure @@ -84,13 +84,13 @@ make modules_install 2. (Perform this step only if you have configured tub3270 as a - module.) Add a line to /etc/modules.conf to automatically + module.) Add a line to /etc/modprobe.conf to automatically load the driver when it's needed. With this line added, you will see login prompts appear on your 3270s as soon as boot is complete (or with emulated 3270s, as soon as you dial into your vm guest using the command "DIAL "). Since the line-mode major number is 227, the line to add to - /etc/modules.conf should be: + /etc/modprobe.conf should be: alias char-major-227 tub3270 3. Define graphic devices to your vm guest machine, if you --- diff/Documentation/scsi/BusLogic.txt 2004-01-19 10:22:54.000000000 +0000 +++ source/Documentation/scsi/BusLogic.txt 2004-02-09 10:39:52.000000000 +0000 @@ -40,10 +40,9 @@ to achieve the full performance that BusLogic SCSI Host Adapters and modern SCSI peripherals are capable of, and to provide a highly robust driver that can be depended upon for high performance mission critical applications. All of -the major performance and error recovery features can be configured from the -Linux kernel command line or at module initialization time, allowing individual -installations to tune driver performance and error recovery to their particular -needs. +the major performance features can be configured from the Linux kernel command +line or at module initialization time, allowing individual installations to +tune driver performance and error recovery to their particular needs. The latest information on Linux support for BusLogic SCSI Host Adapters, as well as the most recent release of this driver and the latest firmware for the @@ -95,10 +94,10 @@ adapter hardware configuration, including the synchronous transfer parameters requested and negotiated with each target device. AutoSCSI settings for Synchronous Negotiation, Wide Negotiation, and Disconnect/Reconnect are - reported for each target device, as well as the status of Tagged Queuing and - Error Recovery. If the same setting is in effect for all target devices, - then a single word or phrase is used; otherwise, a letter is provided for - each target device to indicate the individual status. The following examples + reported for each target device, as well as the status of Tagged Queuing. + If the same setting is in effect for all target devices, then a single word + or phrase is used; otherwise, a letter is provided for each target device to + indicate the individual status. The following examples should clarify this reporting format: Synchronous Negotiation: Ultra @@ -131,9 +130,6 @@ The status of Wide Negotiation, Disconnect/Reconnect, and Tagged Queuing are reported as "Enabled", Disabled", or a sequence of "Y" and "N" letters. - The Error Recovery option is reported as "Default", "Hard Reset", - "Bus Device Reset", "None" or a sequence of "D", "H", "B", and "N" letters. - o Performance Features BusLogic SCSI Host Adapters directly implement SCSI-2 Tagged Queuing, and so @@ -477,48 +473,6 @@ does not cover all the Target Devices, unspecified characters are assumed to be "X". -The BusLogic Driver Error Recovery Option allows for explicitly specifying -the Error Recovery action to be performed when BusLogic_ResetCommand is -called due to a SCSI Command failing to complete successfully. The following -options are available: - -ErrorRecovery:Default - - The "ErrorRecovery:Default" or "ER:Default" option selects between the Hard - Reset and Bus Device Reset options based on the recommendation of the SCSI - Subsystem. - -ErrorRecovery:HardReset - - The "ErrorRecovery:HardReset" or "ER:HardReset" option will initiate a Host - Adapter Hard Reset which also causes a SCSI Bus Reset. - -ErrorRecovery:BusDeviceReset - - The "ErrorRecovery:BusDeviceReset" or "ER:BusDeviceReset" option will send - a Bus Device Reset message to the individual Target Device causing the - error. If Error Recovery is again initiated for this Target Device and no - SCSI Command to this Target Device has completed successfully since the Bus - Device Reset message was sent, then a Hard Reset will be attempted. - -ErrorRecovery:None - - The "ErrorRecovery:None" or "ER:None" option suppresses Error Recovery. - This option should only be selected if a SCSI Bus Reset or Bus Device Reset - will cause the Target Device or a critical operation to suffer a complete - and unrecoverable failure. - -ErrorRecovery: - - The "ErrorRecovery:" or "ER:" option controls - Error Recovery individually for each Target Device. is a - sequence of "D", "H", "B", and "N" characters. "D" selects Default, "H" - selects Hard Reset, "B" selects Bus Device Reset, and "N" selects None. - The first character refers to Target Device 0, the second to Target Device - 1, and so on; if the sequence of "D", "H", "B", and "N" characters does not - cover all the possible Target Devices, unspecified characters are assumed - to be "D". - The BusLogic Driver Miscellaneous Options comprise the following: BusSettleTime: --- diff/Documentation/scsi/aic79xx.txt 2004-01-19 10:22:54.000000000 +0000 +++ source/Documentation/scsi/aic79xx.txt 2004-02-09 10:39:51.000000000 +0000 @@ -210,7 +210,7 @@ INCORRECTLY CAN RENDER YOUR SYSTEM INOPERABLE. USE THEM WITH CAUTION. - Edit the file "modules.conf" in the directory /etc and add/edit a + Edit the file "modprobe.conf" in the directory /etc and add/edit a line containing 'options aic79xx aic79xx=[command[,command...]]' where 'command' is one or more of the following: ----------------------------------------------------------------- --- diff/Documentation/scsi/aic7xxx.txt 2004-01-19 10:22:54.000000000 +0000 +++ source/Documentation/scsi/aic7xxx.txt 2004-02-09 10:39:51.000000000 +0000 @@ -186,7 +186,7 @@ INCORRECTLY CAN RENDER YOUR SYSTEM INOPERABLE. USE THEM WITH CAUTION. - Edit the file "modules.conf" in the directory /etc and add/edit a + Edit the file "modprobe.conf" in the directory /etc and add/edit a line containing 'options aic7xxx aic7xxx=[command[,command...]]' where 'command' is one or more of the following: ----------------------------------------------------------------- --- diff/Documentation/scsi/osst.txt 2002-11-18 10:11:54.000000000 +0000 +++ source/Documentation/scsi/osst.txt 2004-02-09 10:39:52.000000000 +0000 @@ -67,7 +67,7 @@ If you want to have the module autoloaded on access to /dev/osst, you may add something like alias char-major-206 osst -to your /etc/modules.conf (old name: conf.modules). +to your /etc/modprobe.conf (before 2.6: modules.conf). You may find it convenient to create a symbolic link ln -s nosst0 /dev/tape --- diff/Documentation/scsi/scsi_mid_low_api.txt 2003-09-30 15:46:10.000000000 +0100 +++ source/Documentation/scsi/scsi_mid_low_api.txt 2004-02-09 10:39:52.000000000 +0000 @@ -1091,14 +1091,44 @@ * @scp: pointer to scsi command object * @done: function pointer to be invoked on completion * - * Returns 0 on success and 1 if the LLD or the HBA is busy (i.e. run - * out of resources to queue further commands). Other types of errors - * that are detected immediately are flagged by setting scp->result - * to an appropriate value, invoking the 'done' callback, and then - * returning 0 from this function. If the command is not performed - * immediately (and the LLD is starting (or will start) the given - * command) then this function should place 0 in scp->result and - * return 0. + * Returns 0 on success. + * + * If there's a failure, return either: + * + * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or + * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full + * + * On both of these returns, the mid-layer will requeue the I/O + * + * - if the return is SCSI_MLQUEUE_DEVICE_BUSY, only that particular + * device will be paused, and it will be unpaused when a command to + * the device returns (or after a brief delay if there are no more + * outstanding commands to it). Commands to other devices continue + * to be processed normally. + * + * - if the return is SCSI_MLQUEUE_HOST_BUSY, all I/O to the host + * is paused and will be unpaused when any command returns from + * the host (or after a brief delay if there are no outstanding + * commands to the host). + * + * For compatibility with earlier versions of queuecommand, any + * other return value is treated the same as + * SCSI_MLQUEUE_HOST_BUSY. + * + * Other types of errors that are detected immediately may be + * flagged by setting scp->result to an appropriate value, + * invoking the 'done' callback, and then returning 0 from this + * function. If the command is not performed immediately (and the + * LLD is starting (or will start) the given command) then this + * function should place 0 in scp->result and return 0. + * + * Command ownership. If the driver returns zero, it owns the + * command and must take responsibility for ensuring the 'done' + * callback is executed. Note: the driver may call done before + * returning zero, but after it has called done, it may not + * return any value other than zero. If the driver makes a + * non-zero return, it must not execute the command's done + * callback at any time. * * Locks: struct Scsi_Host::host_lock held on entry (with "irqsave") * and is expected to be held on return. --- diff/Documentation/sonypi.txt 2003-09-17 12:28:01.000000000 +0100 +++ source/Documentation/sonypi.txt 2004-02-09 10:39:52.000000000 +0000 @@ -43,7 +43,7 @@ --------------- Several options can be passed to the sonypi driver, either by adding them -to /etc/modules.conf file, when the driver is compiled as a module or by +to /etc/modprobe.conf file, when the driver is compiled as a module or by adding the following to the kernel command line (in your bootloader): sonypi=minor[,verbose[,fnkeyinit[,camera[,compat[,mask[,useinput]]]]]] @@ -109,7 +109,7 @@ ----------- In order to automatically load the sonypi module on use, you can put those -lines in your /etc/modules.conf file: +lines in your /etc/modprobe.conf file: alias char-major-10-250 sonypi options sonypi minor=250 --- diff/Documentation/sound/alsa/ALSA-Configuration.txt 2003-09-30 15:46:10.000000000 +0100 +++ source/Documentation/sound/alsa/ALSA-Configuration.txt 2004-02-09 10:39:52.000000000 +0000 @@ -55,9 +55,10 @@ major - major # for sound driver - default is 116 cards_limit - - specifies card limit # (1-8) - - good for kmod support if you do not want to search - for soundcards which are not installed in your system + - specifies card limit # for auto-loading (1-8) + - default is 1 + - for auto-loading more than 1 card, specify this option + together with snd-card-X aliases. device_mode - specifies permission mask for dynamic sound device filesystem (available only when DEVFS is enabled) @@ -173,8 +174,7 @@ Module for soundcards based on Avance Logic ALS4000 PCI chip. joystick_port - port # for legacy joystick support. - default: 0x200 for the 1st card. - 0 = disabled + 0 = disabled (default), 1 = auto-detect Module supports up to 8 cards, autoprobe and PnP. @@ -199,6 +199,8 @@ Module for soundcards based on Aztech AZF3328 PCI chip. + joystick - Enable joystick (default off) + Module supports up to 8 cards. Module snd-cmi8330 @@ -221,10 +223,11 @@ Module for C-Media CMI8338 and 8738 PCI soundcards. - mpu_port - 0x300 (default),0x310,0x320,0x330, -1 (diable) - fm_port - 0x388 (default), -1 (disable) + mpu_port - 0x300,0x310,0x320,0x330, 0 = disable (default) + fm_port - 0x388 (default), 0 = disable (default) soft_ac3 - Sofware-conversion of raw SPDIF packets (model 033 only) (default = 1) + joystick_port - Joystick port address (0 = disable, 1 = auto-detect) Module supports autoprobe and multiple chips (max 8). @@ -377,6 +380,8 @@ * SoundBlaster PCI 64 * SoundBlaster PCI 128 + joystick - Enable joystick (default off) + Module supports up to 8 cards and autoprobe. Module snd-ens1371 @@ -387,6 +392,9 @@ * SoundBlaster PCI 128 * SoundBlaster Vibra PCI + joystick_port - port # for joystick (0x200,0x208,0x210,0x218), + 0 = disable (default), 1 = auto-detect + Module supports up to 8 cards and autoprobe. Module snd-es968 @@ -451,6 +459,7 @@ use_pm - support the power-management (0 = off, 1 = on, 2 = auto (default)) enable_mpu - enable MPU401 (0 = off, 1 = on, 2 = auto (default)) + joystick - enable joystick (default off) Module supports up to 8 cards and autoprobe. @@ -527,7 +536,7 @@ Module supports up to 8 cards. Note: you need to load the firmware via hdsploader utility included - in alsa-tools package. + in alsa-tools and alsa-firmware packages. Note: snd-page-alloc module does the job which snd-hammerfall-mem module did formerly. It will allocate the buffers in advance @@ -581,7 +590,7 @@ * ALi m5455 ac97_clock - AC'97 codec clock base (0 = auto-detect) - joystick_port - Joystick port # (0 = disabled, 0x200) + joystick - Enable joystick (default off) mpu_port - MPU401 port # (0 = disabled, 0x330,0x300) Module supports autoprobe and multiple bus-master chips (max 8). @@ -991,10 +1000,11 @@ mpu_port - 0x300,0x310,0x320,0x330, otherwise obtain BIOS setup [VIA686A/686B only] + joystick - Enable joystick (default off) [VIA686A/686B only] ac97_clock - AC'97 codec clock base (default 48000Hz) dxs_support - support DXS channels, 0 = auto (defalut), 1 = enable, 2 = disable, - 3 = 48k only + 3 = 48k only, 4 = no VRA [VIA8233/C,8235 only] Module supports autoprobe and multiple bus-master chips (max 8). @@ -1008,13 +1018,20 @@ Note: VIA8233/5 (not VIA8233A) can support DXS (direct sound) channels as the first PCM. On these channels, up to 4 streams can be played at the same time. - As default (dxs_support = 0), 48k fixed rate is chosen since - the output is often noisy except for 48k on some mother - boards due to the bug of BIOS. + As default (dxs_support = 0), 48k fixed rate is chosen + except for the known devices since the output is often + noisy except for 48k on some mother boards due to the + bug of BIOS. Please try once dxs_support=1 and if it works on other - sample rates, please let us know the PCI subsystem - vendor/device id's (output of "lspci -nv"). - If it doesn't work, use dxs_support=3 or dxs_support=2. + sample rates (e.g. 44.1kHz of mp3 playback), please let us + know the PCI subsystem vendor/device id's (output of + "lspci -nv"). + If it doesn't work, try dxs_support=4. If it still doesn't + work and the default setting is ok, dxs_support=3 is the + right choice. If the default setting doesn't work at all, + try dxs_support=2 to disable the DXS channels. + In any cases, please let us know the result and the + subsystem vendor/device ids. Note: for the MPU401 on VIA823x, use snd-mpu401 driver additonally. The mpu_port option is for VIA686 chips only. @@ -1041,11 +1058,13 @@ Module supports up to 8 cards. For loading the firmware, use vxloader utility in alsa-tools - package. You can load the firmware automatically by adding - the following to /etc/modules.conf + and alsa-firmware packages. You can load the firmware automatically + by adding the following to /etc/modprobe.conf - post-install snd-vx222 "/usr/bin/vxload" + install snd-vx222 /sbin/modprobe --first-time -i snd-vx222 && /usr/bin/vxloader + (for 2.2/2.4 kernels, add "post-install /usr/bin/vxloader" to + /etc/modules.conf, instead.) IBL size defines the interrupts period for PCM. The smaller size gives smaller latency but leads to more CPU consumption, too. The size is usually aligned to 126. As default (=0), the smallest @@ -1060,6 +1079,7 @@ irq_mask - IRQ bitmask, specifies the available IRQs as bits (default = 0xffff, all available) irq_list - List of available interrupts (default = -1, not specified) + 4 numbers must be given (if specified). ibl - Capture IBL size. (default = 0, minimum size) Module supports up to 8 cards. The module is compiled only when @@ -1069,13 +1089,15 @@ up /etc/pcmcia/vxpocket.conf. See the sound/pcmcia/vx/vxpocket.c. For loading the firmware, use vxloader utility in alsa-tools - package. + and alsa-firmware packages. The irq_mask and irq_list are provided to avoid allocation of specific IRQs. Usually you don't need to specify them. About capture IBL, see the description of snd-vx222 module. + Note: the driver is build only when CONFIG_ISA is set. + Module snd-vxp440 ----------------- @@ -1083,6 +1105,7 @@ irq_mask - IRQ bitmask, specifies the available IRQs as bits irq_list - List of available interrupts (default = -1, not specified) + 4 numbers must be given (if specified). ibl - Capture IBL size. (default = 0, minimum size) Module supports up to 8 cards. The module is compiled only when @@ -1092,24 +1115,30 @@ up /etc/pcmcia/vxp440.conf. See the sound/pcmcia/vx/vxp440.c. For loading the firmware, use vxloader utility in alsa-tools - package. + and alsa-firmware packages. The irq_mask and irq_list are provided to avoid allocation of specific IRQs. Usually you don't need to specify them. About capture IBL, see the description of snd-vx222 module. + Note: the driver is build only when CONFIG_ISA is set. + Module snd-ymfpci ----------------- Module for Yamaha PCI chips (YMF72x, YMF74x & YMF75x). - mpu_port - 0x300,0x330,0x332,0x334, -1 (disable) by default - fm_port - 0x388,0x398,0x3a0,0x3a8, -1 (disable) by default - rear_switch - enable shared rear/line-in switch (bool) + mpu_port - 0x300,0x330,0x332,0x334, 0 (disable) by default, + 1 (auto-detect for YMF744/754 only) + fm_port - 0x388,0x398,0x3a0,0x3a8, 0 (disable) by default + 1 (auto-detect for YMF744/754 only) + joystick_port - 0x201,0x202,0x204,0x205, 0 (disable) by default, + 1 (auto-detect) + rear_switch - enable shared rear/line-in switch (bool) Module supports autoprobe and multiple chips (max 8). - + The power-management is supported. @@ -1126,160 +1155,49 @@ will be not built in. -modprobe/kmod support -===================== - -The modprobe program must know which modules are used for the -device major numbers. -Native ALSA devices have got default number 116. Thus a line like -'alias char-major-116 snd' must be added to /etc/modules.conf. If you have -compiled the ALSA driver with the OSS/Free emulation code, then you -will need to add lines as explained below: - -The ALSA driver uses soundcore multiplexer for 2.2+ kernels and OSS compatible -devices. You should add line like 'alias char-major-14 soundcore'. - -Example with OSS/Free emulation turned on: - ------ /etc/modules.conf +Module Autoloading Support +========================== -# ALSA portion -alias char-major-116 snd -# OSS/Free portion -alias char-major-14 soundcore - ------ /etc/modules.conf +The ALSA drivers can be loaded automatically on demand by defining +module aliases. The string 'snd-card-%1' is requested for ALSA native +devices where %i is soundcard number from zero to seven. + +To auto-load an ALSA driver for OSS services, define the string +'sound-slot-%i' where %i means the slot number for OSS, which +corresponds to the card index of ALSA. Usually, define this +as the the same card module. + +An example configuration for a single emu10k1 card is like below: +----- /etc/modprobe.conf +alias snd-card-0 snd-emu10k1 +alias sound-slot-0 snd-emu10k1 +----- /etc/modprobe.conf + +The available number of auto-loaded soundcards depends on the module +option "cards_limit" of snd module. As default it's set to 1. +To enable the auto-loading of multiple cards, specify the number of +soundcards in that option. + +When multiple cards are available, it'd better to specify the index +number for each card via module option, too, so that the order of +cards is kept consistent. -After the main multiplexer is loaded, its code requests top-level soundcard -module. String 'snd-card-%i' is requested for native devices where %i is -soundcard number from zero to seven. String 'sound-slot-%i' is requested -for native devices where %i is slot number (for ALSA owner this means soundcard -number). - ------ /etc/modules.conf +An example configuration for two soundcards is like below: +----- /etc/modprobe.conf # ALSA portion +options snd cards_limit=2 alias snd-card-0 snd-interwave alias snd-card-1 snd-ens1371 +options snd-interwave index=0 +options snd-ens1371 index=1 # OSS/Free portion -alias sound-slot-0 snd-card-0 -alias sound-slot-1 snd-card-1 - ------ /etc/modules.conf - -We are finished at this point with the configuration for ALSA native devices, -but you may also need autoloading for ALSA's add-on OSS/Free emulation -modules. At this time only one module does not depend on any others, thus -must be loaded separately - snd-pcm-oss. String 'sound-service-%i-%i' -is requested for OSS/Free service where first %i means slot number -(e.g. card number) and second %i means service number. - ------ /etc/modules.conf - -# OSS/Free portion - card #1 -alias sound-service-0-0 snd-mixer-oss -alias sound-service-0-1 snd-seq-oss -alias sound-service-0-3 snd-pcm-oss -alias sound-service-0-8 snd-seq-oss -alias sound-service-0-12 snd-pcm-oss -# OSS/Free portion - card #2 -alias sound-service-1-0 snd-mixer-oss -alias sound-service-1-3 snd-pcm-oss -alias sound-service-1-12 snd-pcm-oss - ------ /etc/modules.conf - -A complete example for Gravis UltraSound PnP soundcard: - ------ /etc/modules.conf - -# ISA PnP support (don't use IRQs 9,10,11,12,13) -options isapnp isapnp_reserve_irq=9,10,11,12,13 - -# ALSA native device support -alias char-major-116 snd -options snd major=116 cards_limit=1 -alias snd-card-0 snd-interwave -options snd-interwave index=0 id="GusPnP" - -# OSS/Free setup -alias char-major-14 soundcore -alias sound-slot-0 snd-card-0 -alias sound-service-0-0 snd-mixer-oss -alias sound-service-0-1 snd-seq-oss -alias sound-service-0-3 snd-pcm-oss -alias sound-service-0-8 snd-seq-oss -alias sound-service-0-12 snd-pcm-oss - ------ - -A complete example if you want to use more soundcards in one machine -(the configuration below is for Sound Blaster 16 and Gravis UltraSound Classic): - ------ /etc/modules.conf - -# ISA PnP support (don't use IRQs 9,10,11,12,13) -# it's only an example to reserve some IRQs for another hardware -options isapnp isapnp_reserve_irq=9,10,11,12,13 - -# ALSA native device support -alias char-major-116 snd -options snd major=116 cards_limit=2 -alias snd-card-0 snd-gusclassic -alias snd-card-1 snd-sb16 -options snd-gusclassic index=0 id="Gus" \ - port=0x220 irq=5 dma1=6 dma2=7 -options snd-sb16 index=1 id="SB16" - -# OSS/Free setup -alias char-major-14 soundcore -alias sound-slot-0 snd-card-0 -alias sound-service-0-0 snd-mixer-oss -alias sound-service-0-1 snd-seq-oss -alias sound-service-0-3 snd-pcm-oss -alias sound-service-0-8 snd-seq-oss -alias sound-service-0-12 snd-pcm-oss -alias sound-slot-1 snd-card-1 -alias sound-service-1-0 snd-mixer-oss -alias sound-service-1-3 snd-pcm-oss -alias sound-service-1-12 snd-pcm-oss - ------ - -A complete example, two Gravis UltraSound Classic soundcards are installed -in the system: - ------ /etc/modules.conf - -# ALSA native device support -alias char-major-116 snd -options snd major=116 cards_limit=2 -alias snd-card-0 snd-gusclassic -alias snd-card-1 snd-gusclassic -options snd-gusclassic index=0,1 id="Gus1","Gus2" \ - port=0x220,0x240 irq=5,7 dma1=1,5 dma2=3,6 - -# OSS/Free setup -alias char-major-14 soundcore -alias sound-slot-0 snd-card-0 -alias sound-service-0-0 snd-mixer-oss -alias sound-service-0-1 snd-seq-oss -alias sound-service-0-3 snd-pcm-oss -alias sound-service-0-8 snd-seq-oss -alias sound-service-0-12 snd-pcm-oss -alias sound-slot-1 snd-card-1 -alias sound-service-1-0 snd-mixer-oss -alias sound-service-1-3 snd-pcm-oss -alias sound-service-1-12 snd-pcm-oss - ------ - -If you want to autoclean your modules, you should put below line to your -/etc/crontab: - -*/10 * * * * root /sbin/modprobe -rs snd-card-0 snd-card-1; /sbin/rmmod -as +alias sound-slot-0 snd-interwave +alias sound-slot-1 snd-ens1371 +----- /etc/moprobe.conf -You may also want to extend the soundcard list to follow your requirements. +In this example, the interwave card is always loaded as the first card +(index 0) and ens1371 as the second (index 1). ALSA PCM devices to OSS devices mapping --- diff/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl 2004-01-19 10:22:54.000000000 +0000 +++ source/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl 2004-02-09 10:39:52.000000000 +0000 @@ -341,10 +341,6 @@ drivers will be on pci directory, because its API is identical with the standard PCI cards. - - - At this moment, only VX-pocket driver exists. -
@@ -500,14 +496,14 @@ } // (4) - // implemented later - - // (5) strcpy(card->driver, "My Chip"); strcpy(card->shortname, "My Own Chip 123"); sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->ioport, chip->irq); + // (5) + // implemented later + // (6) if ((err = snd_card_register(card)) < 0) { snd_card_free(card); @@ -626,21 +622,8 @@
-
- 4) Create other components, such as mixer, MIDI, etc. - - Here you define the basic components such as - PCM, - mixer (e.g. AC97), - MIDI (e.g. MPU-401), - and other interfaces. - Also, if you want a proc - file, define it here, too. - -
-
- 5) Set the driver ID and name strings. + 4) Set the driver ID and name strings. @@ -667,6 +650,19 @@
+
+ 5) Create other components, such as mixer, MIDI, etc. + + Here you define the basic components such as + PCM, + mixer (e.g. AC97), + MIDI (e.g. MPU-401), + and other interfaces. + Also, if you want a proc + file, define it here, too. + +
+
6) Register the card instance. @@ -1295,11 +1291,11 @@ // check PCI availability (28bit DMA) if ((err = pci_enable_device(pci)) < 0) return err; - if (!pci_dma_supported(pci, 0x0fffffff)) { + if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || + pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { printk(KERN_ERR "error to set 28bit mask DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); chip = snd_magic_kcalloc(mychip_t, 0, GFP_KERNEL); if (chip == NULL) @@ -1413,11 +1409,12 @@ @@ -1914,8 +1911,27 @@ .periods_max = 1024, }; + /* hardware definition */ + static snd_pcm_hardware_t snd_mychip_capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_8000_48000, + .rate_min = 8000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 32768, + .period_bytes_min = 4096, + .period_bytes_max = 32768, + .periods_min = 1, + .periods_max = 1024, + }; + /* open callback */ - static int snd_mychip_pcm_open(snd_pcm_substream_t *substream) + static int snd_mychip_playback_open(snd_pcm_substream_t *substream) { mychip_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; @@ -1926,7 +1942,27 @@ } /* close callback */ - static int snd_mychip_pcm_close(snd_pcm_substream_t *substream) + static int snd_mychip_playback_close(snd_pcm_substream_t *substream) + { + mychip_t *chip = snd_pcm_substream_chip(substream); + // the hardware-specific codes will be here + return 0; + + } + + /* open callback */ + static int snd_mychip_capture_open(snd_pcm_substream_t *substream) + { + mychip_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + runtime->hw = snd_mychip_capture_hw; + // more hardware-initialization will be done here + return 0; + } + + /* close callback */ + static int snd_mychip_capture_close(snd_pcm_substream_t *substream) { mychip_t *chip = snd_pcm_substream_chip(substream); // the hardware-specific codes will be here @@ -2005,6 +2041,18 @@ .pointer = snd_mychip_pcm_pointer, }; + /* operators */ + static snd_pcm_ops_t snd_mychip_capture_ops = { + .open = snd_mychip_capture_open, + .close = snd_mychip_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_mychip_pcm_hw_params, + .hw_free = snd_mychip_pcm_hw_free, + .prepare = snd_mychip_pcm_prepare, + .trigger = snd_mychip_pcm_trigger, + .pointer = snd_mychip_pcm_pointer, + }; + /* * definitions of capture are omitted here... */ @@ -3982,13 +4030,18 @@ static int snd_mychip_ac97(mychip_t *chip) { + ac97_bus_t bus, *pbus; ac97_t ac97; + int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_mychip_ac97_write; + bus.read = snd_mychip_ac97_read; + if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0) + return err; memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_mychip_ac97_write; - ac97.read = snd_mychip_ac97_read; ac97.private_data = chip; - return snd_ac97_mixer(card, &ac97, &chip->ac97); + return snd_ac97_mixer(pbus, &ac97, &chip->ac97); } ]]> @@ -4000,9 +4053,29 @@
Constructor - For creating an ac97 instance, call - snd_ac97_mixer() with an ac97_t - record, in which the callbacks and the private_data is set. + For creating an ac97 instance, first call snd_ac97_bus + with ac97_bus_t record including callback functions. + + + + + + + + The bus record is shared among all belonging ac97 instances. + + + + And then call snd_ac97_mixer() with an ac97_t + record together with the bus pointer created above. @@ -4011,16 +4084,16 @@ int err; memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_mychip_ac97_write; - ac97.read = snd_mychip_ac97_read; ac97.private_data = chip; - snd_ac97_mixer(card, &ac97, &chip->ac97); + snd_ac97_mixer(bus, &ac97, &chip->ac97); ]]> where chip->ac97 is the pointer of a newly created ac97_t instance. + In this case, the chip pointer is set as the private data, so that + the read/write callback functions can refer to this chip instance. This instance is not necessarily stored in the chip record. When you need to change the register values from the driver, or need the suspend/resume of ac97 codecs, keep this @@ -4094,14 +4167,11 @@ The wait callback is used for a certain wait at the standard initialization of the codec. If the chip requires the extra wait-time, define this callback. - This callback is always non-atomic, because it's never called - in the resume mode. The init callback is used for - additional initialization of the codec. This callback is called - after the reset, and should be atomic in the resume mode. + additional initialization of the codec.
@@ -4674,10 +4744,7 @@ - Note that you have to pre-allocate to use this function - (i.e. you cannot use this function for - - a scatter-gather buffer). + Note that you have to pre-allocate to use this function.
@@ -4905,6 +4972,8 @@ When a SG-handler is used, you need to set snd_pcm_sgbuf_ops_page as the page callback. + (See + page callback section.) @@ -4999,13 +5068,14 @@ where the second argument (chip) is the - private data to be used in the callbacks and the third + private data to be used in the callbacks. The third parameter + specifies the read buffer size and the fourth (my_proc_read) is the callback function, which is defined like --- diff/Documentation/sound/alsa/OSS-Emulation.txt 2003-09-30 15:46:10.000000000 +0100 +++ source/Documentation/sound/alsa/OSS-Emulation.txt 2004-02-09 10:39:52.000000000 +0000 @@ -1,7 +1,7 @@ NOTES ON KERNEL OSS-EMULATION ============================= - Jan. 9, 2003 Takashi Iwai + Jan. 22, 2004 Takashi Iwai Modules @@ -13,32 +13,20 @@ When you need to access the OSS PCM, mixer or sequencer devices, the corresponding module has to be loaded. -For loading these modules automatically, define the aliases in -/etc/modules.conf like below: - - alias sound-service-0-0 snd-mixer-oss - alias sound-service-0-1 snd-seq-oss - alias sound-service-0-3 snd-pcm-oss - alias sound-service-0-8 snd-seq-oss - alias sound-service-0-12 snd-pcm-oss - -Then the access to an OSS device file such as /dev/dsp0 triggers to -load the necessary module via KMOD. - -For auto-loading the secondary card device like /dev/dsp1, the -following aliases are necessary in addition: - - alias sound-service-1-0 snd-mixer-oss - alias sound-service-1-3 snd-pcm-oss - alias sound-service-1-12 snd-pcm-oss - -Here you don't need to define service-1-1 and service-1-8 because -there is only one sequencer device. -Similarly, you can add definitions for the third or later cards as -sound-service-X-Y. - -The OSS-MIDI is emulated directly in the ALSA rawmidi module, -therefore no extra module exists for that purpose. +These modules are loaded automatically when the corresponding service +is called. The alias is defined sound-service-x-y, where x and y are +the card number and the minor unit number. Usually you don't have to +define these aliases by yourself. + +Only necessary step for auto-loading of OSS modules is to define the +card alias in /etc/modprobe.conf, such as + + alias sound-slot-0 snd-emu10k1 + +As the second card, define sound-slot-1 as well. +Note that you can't use the aliased name as the target name (i.e. +"alias sound-slot-0 snd-card-0" doesn't work any more like the old +modutils). The currently available OSS configuration is shown in /proc/asound/oss/sndstat. This shows in the same syntax of @@ -152,8 +140,7 @@ direct don't use plugins block force block open mode non-block force non-block open mode - whole-frag write only whole fragments (optimization affecting - playback only) + partial-frag write also partial fragments (affects playback only) no-silence do not fill silence ahead to avoid clicks The disable option is useful when one stream direction (playback or @@ -188,7 +175,7 @@ options snd-pcm-oss nonblock_open=1 -The whole-frag and no-silence commands have been added recently. +The partial-frag and no-silence commands have been added recently. Both commands are for optimization use only. The former command specifies to invoke the write transfer only when the whole fragment is filled. The latter stops writing the silence data ahead --- diff/Documentation/sound/alsa/SB-Live-mixer.txt 2002-10-16 04:27:11.000000000 +0100 +++ source/Documentation/sound/alsa/SB-Live-mixer.txt 2004-02-09 10:39:52.000000000 +0000 @@ -101,15 +101,15 @@ The result is forwarded to the ADC capture FIFO (thus to the standard capture PCM device). -name='Surround Digital Playback Volume',index=0 +name='Surround Playback Volume',index=0 This control is used to attenuate samples for left and right rear PCM FX-bus accumulators. ALSA uses accumulators 2 and 3 for left and right rear PCM samples. The result samples are forwarded to the rear I2S DACs. These DACs operate separately (they are not inside the AC97 codec). -name='Surround Digital Capture Volume',index=0 -name='Surround Digital Capture Switch',index=0 +name='Surround Capture Volume',index=0 +name='Surround Capture Switch',index=0 These controls are used to attenuate samples for left and right rear PCM FX-bus accumulators. ALSA uses accumulators 2 and 3 for left and right rear PCM samples. @@ -172,13 +172,13 @@ digital inputs (usually used by a CDROM drive). The result samples are forwarded to the ADC capture FIFO (thus to the standard capture PCM device). -name='IEC958 Optical Playback Volume',index=0 +name='IEC958 LiveDrive Playback Volume',index=0 This control is used to attenuate samples from left and right IEC958 optical digital input. The result samples are forwarded to the front DAC PCM slots of the AC97 codec. -name='IEC958 Optical Capture Volume',index=0 +name='IEC958 LiveDrive Capture Volume',index=0 This control is used to attenuate samples from left and right IEC958 optical digital inputs. The result samples are forwarded to the ADC capture FIFO --- diff/Documentation/sound/oss/AWE32 2002-10-16 04:28:25.000000000 +0100 +++ source/Documentation/sound/oss/AWE32 2004-02-09 10:39:52.000000000 +0000 @@ -47,12 +47,12 @@ Copy it to a directory of your choice, and unpack it there. -4) Edit /etc/modules.conf, and insert the following lines at the end of the +4) Edit /etc/modprobe.conf, and insert the following lines at the end of the file: alias sound-slot-0 sb alias sound-service-0-1 awe_wave - post-install awe_wave /usr/local/bin/sfxload PATH_TO_SOUND_BANK_FILE + install awe_wave /sbin/modprobe --first-time -i awe_wave && /usr/local/bin/sfxload PATH_TO_SOUND_BANK_FILE You will of course have to change "PATH_TO_SOUND_BANK_FILE" to the full path of of the sound bank file. That will enable the Sound Blaster and AWE --- diff/Documentation/sound/oss/AudioExcelDSP16 2002-10-16 04:27:08.000000000 +0100 +++ source/Documentation/sound/oss/AudioExcelDSP16 2004-02-09 10:39:52.000000000 +0000 @@ -41,7 +41,7 @@ (0x300, 0x310, 0x320 or 0x330) mpu_irq MPU-401 irq line (5, 7, 9, 10 or 0) -The /etc/modules.conf will have lines like this: +The /etc/modprobe.conf will have lines like this: options opl3 io=0x388 options ad1848 io=0x530 irq=11 dma=3 @@ -51,11 +51,11 @@ ad1848 are the corresponding options for the MSS and OPL3 modules. Loading MSS and OPL3 needs to pre load the aedsp16 module to set up correctly -the sound card. Installation dependencies must be written in the modules.conf +the sound card. Installation dependencies must be written in the modprobe.conf file: -pre-install ad1848 modprobe aedsp16 -pre-install opl3 modprobe aedsp16 +install ad1848 /sbin/modprobe aedsp16 && /sbin/modprobe -i ad1848 +install opl3 /sbin/modprobe aedsp16 && /sbin/modprobe -i opl3 Then you must load the sound modules stack in this order: sound -> aedsp16 -> [ ad1848, opl3 ] --- diff/Documentation/sound/oss/CMI8330 2004-01-19 10:22:54.000000000 +0000 +++ source/Documentation/sound/oss/CMI8330 2004-02-09 10:39:52.000000000 +0000 @@ -143,7 +143,7 @@ -Alma Chao suggests the following /etc/modules.conf: +Alma Chao suggests the following /etc/modprobe.conf: alias sound ad1848 alias synth0 opl3 --- diff/Documentation/sound/oss/Introduction 2004-01-19 10:22:54.000000000 +0000 +++ source/Documentation/sound/oss/Introduction 2004-02-09 10:39:52.000000000 +0000 @@ -168,7 +168,7 @@ ========= If loading via modprobe, these common files are automatically loaded -when requested by modprobe. For example, my /etc/modules.conf contains: +when requested by modprobe. For example, my /etc/modprobe.conf contains: alias sound sb options sb io=0x240 irq=9 dma=3 dma16=5 mpu_io=0x300 @@ -228,7 +228,7 @@ driver, you should do the following: 1. remove sound modules (detailed above) -2. remove the sound modules from /etc/modules.conf +2. remove the sound modules from /etc/modprobe.conf 3. move the sound modules from /lib/modules//misc (for example, I make a /lib/modules//misc/tmp directory and copy the sound module files to that @@ -265,7 +265,7 @@ sb.o could be copied (or symlinked) to sb1.o for the second SoundBlaster. -2. Make a second entry in /etc/modules.conf, for example, +2. Make a second entry in /etc/modprobe.conf, for example, sound1 or sb1. This second entry should refer to the new module names for example sb1, and should include the I/O, etc. for the second sound card. @@ -369,7 +369,7 @@ 2) On the command line when using insmod or in a bash script using command line calls to load sound. -3) In /etc/modules.conf when using modprobe. +3) In /etc/modprobe.conf when using modprobe. 4) Via Red Hat's GPL'd /usr/sbin/sndconfig program (text based). --- diff/Documentation/sound/oss/MAD16 2002-10-16 04:29:06.000000000 +0100 +++ source/Documentation/sound/oss/MAD16 2004-02-09 10:39:52.000000000 +0000 @@ -1,4 +1,5 @@ -(This recipe has been edited to update the configuration symbols.) +(This recipe has been edited to update the configuration symbols, + and change over to modprobe.conf for 2.6) From: Shaw Carruthers @@ -20,9 +21,9 @@ CONFIG_SOUND_MAD16=m CONFIG_SOUND_YM3812=m -modules.conf has: +modprobe.conf has: -alias char-major-14 mad16 +alias char-major-14-* mad16 options sb mad16=1 options mad16 io=0x530 irq=7 dma=0 dma16=1 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0 --- diff/Documentation/sound/oss/Maestro3 2002-10-16 04:28:34.000000000 +0100 +++ source/Documentation/sound/oss/Maestro3 2004-02-09 10:39:52.000000000 +0000 @@ -64,7 +64,7 @@ installed with the rest of the modules for the kernel on the system. Typically this will be in /lib/modules/ somewhere. 'alias sound-slot-0 maestro3' should also be added to your module configs (typically -/etc/modules.conf) if you're using modular OSS/Lite sound and want to +/etc/modprobe.conf) if you're using modular OSS/Lite sound and want to default to using a maestro3 chip. There are very few options to the driver. One is 'debug' which will --- diff/Documentation/sound/oss/OPL3-SA2 2002-10-16 04:27:14.000000000 +0100 +++ source/Documentation/sound/oss/OPL3-SA2 2004-02-09 10:39:52.000000000 +0000 @@ -162,7 +162,7 @@ modprobe opl3 io=0x388 See the section "Automatic Module Loading" below for how to set up -/etc/modules.conf to automate this. +/etc/modprobe.conf to automate this. An important thing to remember that the opl3sa2 module's io argument is for it's own control port, which handles the card's master mixer for @@ -196,7 +196,7 @@ Lastly, if you're using modules and want to set up automatic module loading with kmod, the kernel module loader, here is the section I -currently use in my modules.conf file: +currently use in my modprobe.conf file: # Sound alias sound-slot-0 opl3sa2 --- diff/Documentation/sound/oss/Opti 2002-10-16 04:27:53.000000000 +0100 +++ source/Documentation/sound/oss/Opti 2004-02-09 10:39:52.000000000 +0000 @@ -18,7 +18,7 @@ If you have another OS installed on your computer it is recommended that Linux and the other OS use the same resources. -Also, it is recommended that resources specified in /etc/modules.conf +Also, it is recommended that resources specified in /etc/modprobe.conf and resources specified in /etc/isapnp.conf agree. Compiling the sound driver @@ -68,9 +68,9 @@ Using kmod and autoloading the sound driver ------------------------------------------- Comment: as of linux-2.1.90 kmod is replacing kerneld. -The config file '/etc/modules.conf' is used as before. +The config file '/etc/modprobe.conf' is used as before. -This is the sound part of my /etc/modules.conf file. +This is the sound part of my /etc/modprobe.conf file. Following that I will explain each line. alias mixer0 mad16 @@ -80,7 +80,7 @@ options sb mad16=1 options mad16 irq=10 dma=0 dma16=1 io=0x530 joystick=1 cdtype=0 options opl3 io=0x388 -post-install mad16 /sbin/ad1848_mixer_reroute 14 8 15 3 16 6 +install mad16 /sbin/modprobe -i mad16 && /sbin/ad1848_mixer_reroute 14 8 15 3 16 6 If you have an MPU daughtercard or onboard MPU you will want to add to the "options mad16" line - eg --- diff/Documentation/sound/oss/PAS16 2004-01-19 10:22:54.000000000 +0000 +++ source/Documentation/sound/oss/PAS16 2004-02-09 10:39:52.000000000 +0000 @@ -129,7 +129,7 @@ You can then get OPL3 functionality by issuing the command: insmod opl3 In addition, you must either add the following line to - /etc/modules.conf: + /etc/modprobe.conf: options opl3 io=0x388 or else add the following line to /etc/lilo.conf: opl3=0x388 @@ -159,5 +159,5 @@ append="pas2=0x388,10,3,-1,0,-1,-1,-1 opl3=0x388" If sound is built totally modular, the above options may be -specified in /etc/modules.conf for pas2.o, sb.o and opl3.o +specified in /etc/modprobe.conf for pas2, sb and opl3 respectively. --- diff/Documentation/sound/oss/README.modules 2002-10-16 04:27:53.000000000 +0100 +++ source/Documentation/sound/oss/README.modules 2004-02-09 10:39:52.000000000 +0000 @@ -26,10 +26,10 @@ drivers/sound dir. Now one simply configures and makes one's kernel and modules in the usual way. - Then, add to your /etc/modules.conf something like: + Then, add to your /etc/modprobe.conf something like: -alias char-major-14 sb -post-install sb /sbin/modprobe "-k" "adlib_card" +alias char-major-14-* sb +install sb /sbin/modprobe -i sb && /sbin/modprobe adlib_card options sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330 options adlib_card io=0x388 # FM synthesizer @@ -65,12 +65,12 @@ Note that at present there is no way to configure the io, irq and other parameters for the modular drivers as one does for the wired drivers.. One needs to pass the modules the necessary parameters as arguments, either -with /etc/modules.conf or with command-line args to modprobe, e.g. +with /etc/modprobe.conf or with command-line args to modprobe, e.g. -modprobe -k sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330 -modprobe -k adlib_card io=0x388 +modprobe sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330 +modprobe adlib_card io=0x388 - recommend using /etc/modules.conf. + recommend using /etc/modprobe.conf. Persistent DMA Buffers: @@ -88,7 +88,7 @@ To make the sound driver use persistent DMA buffers we need to pass the sound.o module a "dmabuf=1" command-line argument. This is normally done -in /etc/modules.conf like so: +in /etc/modprobe.conf like so: options sound dmabuf=1 --- diff/Documentation/sound/oss/Wavefront 2004-01-19 10:22:54.000000000 +0000 +++ source/Documentation/sound/oss/Wavefront 2004-02-09 10:39:52.000000000 +0000 @@ -189,16 +189,15 @@ 6) How do I configure my card ? ************************************************************ -You need to edit /etc/modules.conf. Here's mine (edited to show the +You need to edit /etc/modprobe.conf. Here's mine (edited to show the relevant details): # Sound system - alias char-major-14 wavefront + alias char-major-14-* wavefront alias synth0 wavefront alias mixer0 cs4232 alias audio0 cs4232 - pre-install wavefront modprobe "-k" "cs4232" - post-install wavefront modprobe "-k" "opl3" + install wavefront /sbin/modprobe cs4232 && /sbin/modprobe -i wavefront && /sbin/modprobe opl3 options wavefront io=0x200 irq=9 options cs4232 synthirq=9 synthio=0x200 io=0x530 irq=5 dma=1 dma2=0 options opl3 io=0x388 --- diff/Documentation/sysctl/fs.txt 2003-01-02 10:43:02.000000000 +0000 +++ source/Documentation/sysctl/fs.txt 2004-02-09 10:39:52.000000000 +0000 @@ -138,3 +138,13 @@ can have. You only need to increase super-max if you need to mount more filesystems than the current value in super-max allows you to. + +============================================================== + +aio-nr & aio-max-nr: + +aio-nr shows the current system-wide number of asynchronous io +requests. aio-max-nr allows you to change the maximum value +aio-nr can grow to. + +============================================================== --- diff/Documentation/sysctl/kernel.txt 2004-02-09 10:36:07.000000000 +0000 +++ source/Documentation/sysctl/kernel.txt 2004-02-09 10:39:52.000000000 +0000 @@ -254,8 +254,8 @@ printk_ratelimit: Some warning messages are rate limited. printk_ratelimit specifies -the minimum length of time between these messages, by default we -allow one every 5 seconds. +the minimum length of time between these messages (in jiffies), by +default we allow one every 5 seconds. A value of 0 will disable rate limiting. --- diff/Documentation/usb/acm.txt 2002-10-16 04:27:22.000000000 +0100 +++ source/Documentation/usb/acm.txt 2004-02-09 10:39:52.000000000 +0000 @@ -28,7 +28,7 @@ 1. Usage ~~~~~~~~ - The drivers/usb/acm.c drivers works with USB modems and USB ISDN terminal + The drivers/usb/class/cdc-acm.c drivers works with USB modems and USB ISDN terminal adapters that conform to the Universal Serial Bus Communication Device Class Abstract Control Model (USB CDC ACM) specification. @@ -65,9 +65,9 @@ To use the modems you need these modules loaded: - usbcore.o - usb-[uo]hci.o or uhci.o - acm.o + usbcore.ko + uhci-hcd.ko ohci-hcd.ko or ehci-hcd.ko + cdc-acm.ko After that, the modem[s] should be accessible. You should be able to use minicom, ppp and mgetty with them. --- diff/Documentation/usb/scanner.txt 2003-05-21 11:49:49.000000000 +0100 +++ source/Documentation/usb/scanner.txt 2004-02-09 10:39:52.000000000 +0000 @@ -146,14 +146,14 @@ options scanner vendor=0x#### product=0x**** -to the /etc/modules.conf file replacing the #'s and the *'s with the +to the /etc/modprobe.conf file replacing the #'s and the *'s with the correct IDs. The IDs can be retrieved from the messages file or using "cat /proc/bus/usb/devices". If the default timeout is too low, i.e. there are frequent "timeout" messages, you may want to increase the timeout manually by using the parameter "read_timeout". The time is given in seconds. This is an example for -modules.conf with a timeout of 60 seconds: +modprobe.conf with a timeout of 60 seconds: options scanner read_timeout=60 --- diff/Documentation/video4linux/CQcam.txt 2003-10-09 09:47:33.000000000 +0100 +++ source/Documentation/video4linux/CQcam.txt 2004-02-09 10:39:52.000000000 +0000 @@ -62,7 +62,7 @@ The configuration requires module configuration and device configuration. I like kmod or kerneld process with the -/etc/modules.conf file so the modules can automatically load/unload as +/etc/modprobe.conf file so the modules can automatically load/unload as they are used. The video devices could already exist, be generated using MAKEDEV, or need to be created. The following sections detail these procedures. @@ -71,15 +71,15 @@ 2.1 Module Configuration Using modules requires a bit of work to install and pass the -parameters. Understand that entries in /etc/modules.conf of: +parameters. Understand that entries in /etc/modprobe.conf of: alias parport_lowlevel parport_pc options parport_pc io=0x378 irq=none alias char-major-81 videodev alias char-major-81-0 c-qcam -will cause the kmod/kerneld/modprobe to do certain things. If you are -using kmod or kerneld, then a request for a 'char-major-81-0' will cause +will cause the kmod/modprobe to do certain things. If you are +using kmod, then a request for a 'char-major-81-0' will cause the 'c-qcam' module to load. If you have other video sources with modules, you might want to assign the different minor numbers to different modules. --- diff/Documentation/video4linux/Zoran 2003-09-30 15:46:10.000000000 +0100 +++ source/Documentation/video4linux/Zoran 2004-02-09 10:39:52.000000000 +0000 @@ -233,7 +233,7 @@ option with X being the card number as given in the previous section. To have more than one card, use card=X1[,X2[,X3,[X4[..]]]] -To automate this, add the following to your /etc/modules.conf: +To automate this, add the following to your /etc/modprobe.conf: options zr36067 card=X1[,X2[,X3[,X4[..]]]] alias char-major-81-0 zr36067 --- diff/Documentation/video4linux/bttv/Modules.conf 2002-10-16 04:28:23.000000000 +0100 +++ source/Documentation/video4linux/bttv/Modules.conf 2004-02-09 10:39:52.000000000 +0000 @@ -1,3 +1,6 @@ +# For modern kernels (2.6 or above), this belongs in /etc/modprobe.conf +# For for 2.4 kernels or earlier, this belongs in /etc/modules.conf. + # i2c alias char-major-89 i2c-dev options i2c-core i2c_debug=1 --- diff/Documentation/video4linux/bttv/README 2004-02-09 10:36:07.000000000 +0000 +++ source/Documentation/video4linux/bttv/README 2004-02-09 10:39:52.000000000 +0000 @@ -22,7 +22,7 @@ cards is in CARDLIST.bttv If bttv takes very long to load (happens sometimes with the cheap -cards which have no tuner), try adding this to your modules.conf: +cards which have no tuner), try adding this to your modprobe.conf: options i2c-algo-bit bit_test=1 For the WinTV/PVR you need one firmware file from the driver CD: --- diff/Documentation/video4linux/meye.txt 2003-11-25 15:24:57.000000000 +0000 +++ source/Documentation/video4linux/meye.txt 2004-02-09 10:39:52.000000000 +0000 @@ -42,7 +42,7 @@ --------------- Several options can be passed to the meye driver, either by adding them -to /etc/modules.conf file, when the driver is compiled as a module, or +to /etc/modprobe.conf file, when the driver is compiled as a module, or by adding the following to the kernel command line (in your bootloader): meye=gbuffers[,gbufsize[,video_nr]] @@ -59,7 +59,7 @@ ----------- In order to automatically load the meye module on use, you can put those lines -in your /etc/modules.conf file: +in your /etc/modprobe.conf file: alias char-major-81 videodev alias char-major-81-0 meye --- diff/MAINTAINERS 2004-02-09 10:36:07.000000000 +0000 +++ source/MAINTAINERS 2004-02-09 10:39:57.000000000 +0000 @@ -1188,6 +1188,12 @@ W: http://developer.osdl.org/rddunlap/kj-patches/ S: Maintained +KGDB FOR I386 PLATFORM +P: George Anzinger +M: george@mvista.com +L: linux-net@vger.kernel.org +S: Supported + KERNEL NFSD P: Neil Brown M: neilb@cse.unsw.edu.au --- diff/Makefile 2004-02-09 10:36:07.000000000 +0000 +++ source/Makefile 2004-02-09 10:39:57.000000000 +0000 @@ -1,8 +1,8 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 2 -EXTRAVERSION = -NAME=Feisty Dunnart +EXTRAVERSION = -mm1 +NAME=Geriatric Wombat # *DOCUMENTATION* # To see a list of typical targets execute "make help" @@ -444,6 +444,7 @@ ifdef CONFIG_DEBUG_INFO CFLAGS += -g +AFLAGS += -g endif # warn about C99 declaration after statement @@ -830,7 +831,7 @@ cmd_cscope-file = $(all-sources) > cscope.files quiet_cmd_cscope = MAKE cscope.out - cmd_cscope = cscope -k -b + cmd_cscope = cscope -k -b -q cscope: FORCE $(call cmd,cscope-file) --- diff/arch/alpha/oprofile/common.c 2003-06-30 10:07:32.000000000 +0100 +++ source/arch/alpha/oprofile/common.c 2004-02-09 10:39:50.000000000 +0000 @@ -57,7 +57,7 @@ /* Compute the mask of enabled counters. */ for (i = e = 0; i < model->num_counters; ++i) - if (ctr[0].enabled) + if (ctr[i].enabled) e |= 1 << i; reg.enable = e; --- diff/arch/arm/kernel/process.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/arm/kernel/process.c 2004-02-09 10:39:50.000000000 +0000 @@ -264,7 +264,7 @@ if (!thread) thread = ll_alloc_task_struct(); -#ifdef CONFIG_SYSRQ +#ifdef CONFIG_MAGIC_SYSRQ /* * The stack must be cleared if you want SYSRQ-T to * give sensible stack usage information --- diff/arch/arm26/Kconfig 2003-09-30 15:46:11.000000000 +0100 +++ source/arch/arm26/Kconfig 2004-02-09 10:39:50.000000000 +0000 @@ -216,11 +216,6 @@ source "drivers/char/Kconfig" -config KBDMOUSE - bool - depends on ARCH_ACORN && BUSMOUSE=y - default y - source "drivers/media/Kconfig" source "fs/Kconfig" --- diff/arch/arm26/kernel/process.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/arm26/kernel/process.c 2004-02-09 10:39:50.000000000 +0000 @@ -257,7 +257,7 @@ if (!thread) thread = ll_alloc_task_struct(); -#ifdef CONFIG_SYSRQ +#ifdef CONFIG_MAGIC_SYSRQ /* * The stack must be cleared if you want SYSRQ-T to * give sensible stack usage information --- diff/arch/cris/arch-v10/drivers/ethernet.c 2003-07-11 09:39:49.000000000 +0100 +++ source/arch/cris/arch-v10/drivers/ethernet.c 2004-02-09 10:39:50.000000000 +0000 @@ -482,7 +482,7 @@ /* Register device */ err = register_netdev(dev); if (err) { - kfree(dev); + free_netdev(dev); return err; } --- diff/arch/h8300/lib/checksum.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/h8300/lib/checksum.c 2004-02-09 10:39:50.000000000 +0000 @@ -32,7 +32,6 @@ of the assembly has to go. */ #include -#include static inline unsigned short from32to16(unsigned long x) { --- diff/arch/h8300/platform/h8300h/ints.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/h8300/platform/h8300h/ints.c 2004-02-09 10:39:50.000000000 +0000 @@ -140,8 +140,9 @@ if (use_kmalloc) irq_handle = (irq_handler_t *)kmalloc(sizeof(irq_handler_t), GFP_ATOMIC); else { - irq_handle = alloc_bootmem(sizeof(irq_handler_t)); - (unsigned long)irq_handle |= 0x80000000; /* bootmem allocater */ + /* use bootmem allocater */ + irq_handle = (irq_handler_t *)alloc_bootmem(sizeof(irq_handler_t)); + irq_handle = (irq_handler_t *)((unsigned long)irq_handle | 0x80000000); } if (irq_handle == NULL) @@ -230,11 +231,9 @@ { int i = *(loff_t *) v; - if (i < NR_IRQS) { - if (irq_list[i]) { - seq_printf(p, "%3d: %10u ",i,irq_list[i]->count); - seq_printf(p, "%s\n", irq_list[i]->devname); - } + if ((i < NR_IRQS) && (irq_list[i]!=NULL)) { + seq_printf(p, "%3d: %10u ",i,irq_list[i]->count); + seq_printf(p, "%s\n", irq_list[i]->devname); } return 0; --- diff/arch/h8300/platform/h8s/ints.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/h8300/platform/h8s/ints.c 2004-02-09 10:39:50.000000000 +0000 @@ -178,8 +178,9 @@ if (use_kmalloc) irq_handle = (irq_handler_t *)kmalloc(sizeof(irq_handler_t), GFP_ATOMIC); else { - irq_handle = alloc_bootmem(sizeof(irq_handler_t)); - (unsigned long)irq_handle |= 0x80000000; /* bootmem allocater */ + /* use bootmem allocater */ + irq_handle = (irq_handler_t *)alloc_bootmem(sizeof(irq_handler_t)); + irq_handle = (irq_handler_t *)((unsigned long)irq_handle | 0x80000000); } if (irq_handle == NULL) @@ -282,11 +283,9 @@ { int i = *(loff_t *) v; - if (i < NR_IRQS) { - if (irq_list[i]) { - seq_printf(p, "%3d: %10u ",i,irq_list[i]->count); - seq_printf(p, "%s\n", irq_list[i]->devname); - } + if ((i < NR_IRQS) && (irq_list[i] !=NULL)) { + seq_printf(p, "%3d: %10u ",i,irq_list[i]->count); + seq_printf(p, "%s\n", irq_list[i]->devname); } return 0; --- diff/arch/i386/Kconfig 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/i386/Kconfig 2004-02-09 10:39:50.000000000 +0000 @@ -43,6 +43,15 @@ help Choose this option if your computer is a standard PC or compatible. +config X86_ELAN + bool "AMD Elan" + help + Select this for an AMD Elan processor. + + Do not use this option for K6/Athlon/Opteron processors! + + If unsure, choose "PC-compatible" instead. + config X86_VOYAGER bool "Voyager (NCR)" help @@ -130,278 +139,318 @@ default y depends on SMP && X86_ES7000 && MPENTIUMIII -choice - prompt "Processor family" - default M686 +if !X86_ELAN -config M386 - bool "386" - ---help--- - This is the processor type of your CPU. This information is used for - optimizing purposes. In order to compile a kernel that can run on - all x86 CPU types (albeit not optimally fast), you can specify - "386" here. - - The kernel will not necessarily run on earlier architectures than - the one you have chosen, e.g. a Pentium optimized kernel will run on - a PPro, but not necessarily on a i486. - - Here are the settings recommended for greatest speed: - - "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX, Cyrix/TI - 486DLC/DLC2, UMC 486SX-S and NexGen Nx586. Only "386" kernels - will run on a 386 class machine. - - "486" for the AMD/Cyrix/IBM/Intel 486DX/DX2/DX4 or - SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or U5S. - - "586" for generic Pentium CPUs lacking the TSC - (time stamp counter) register. - - "Pentium-Classic" for the Intel Pentium. - - "Pentium-MMX" for the Intel Pentium MMX. - - "Pentium-Pro" for the Intel Pentium Pro. - - "Pentium-II" for the Intel Pentium II or pre-Coppermine Celeron. - - "Pentium-III" for the Intel Pentium III or Coppermine Celeron. - - "Pentium-4" for the Intel Pentium 4 or P4-based Celeron. - - "K6" for the AMD K6, K6-II and K6-III (aka K6-3D). - - "Athlon" for the AMD K7 family (Athlon/Duron/Thunderbird). - - "Crusoe" for the Transmeta Crusoe series. - - "Winchip-C6" for original IDT Winchip. - - "Winchip-2" for IDT Winchip 2. - - "Winchip-2A" for IDT Winchips with 3dNow! capabilities. - - "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3. - - "VIA C3-2 for VIA C3-2 "Nehemiah" (model 9 and above). +menu "Processor support" + +comment "Select all processors your kernel should support" - If you don't know what to do, choose "386". +config CPU_386 + bool "386" + default n + help + Select this for a 386 series processor. -config M486 +config CPU_486 bool "486" + default y help Select this for a 486 series processor, either Intel or one of the compatible processors from AMD, Cyrix, IBM, or Intel. Includes DX, DX2, and DX4 variants; also SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or U5S. -config M586 +config CPU_586 bool "586/K5/5x86/6x86/6x86MX" + default y help - Select this for an 586 or 686 series processor such as the AMD K5, - the Intel 5x86 or 6x86, or the Intel 6x86MX. This choice does not - assume the RDTSC (Read Time Stamp Counter) instruction. + Select this for a non-Intel 586 or 686 series processor such as + the AMD K5 or the Cyrix 6x86MX. + + Several CPUs that have their own options below (e.g. AMD K6, + Duron, Athlon and Opteeron, IDT Winchip, Cyrix III and + VIA C3) do _not_ need this option. -config M586TSC + This choice does not assume the RDTSC (Read Time Stamp Counter) + instruction. + +config CPU_586TSC bool "Pentium-Classic" + default y help Select this for a Pentium Classic processor with the RDTSC (Read - Time Stamp Counter) instruction for benchmarking. + Time Stamp Counter) instruction. -config M586MMX +config CPU_586MMX bool "Pentium-MMX" + default y help Select this for a Pentium with the MMX graphics/multimedia extended instructions. -config M686 +config CPU_686 bool "Pentium-Pro" + default y help - Select this for Intel Pentium Pro chips. This enables the use of - Pentium Pro extended instructions, and disables the init-time guard - against the f00f bug found in earlier Pentiums. + Select this for Intel Pentium Pro chips. -config MPENTIUMII +config CPU_PENTIUMII bool "Pentium-II/Celeron(pre-Coppermine)" + default y help Select this for Intel chips based on the Pentium-II and - pre-Coppermine Celeron core. This option enables an unaligned - copy optimization, compiles the kernel with optimization flags - tailored for the chip, and applies any applicable Pentium Pro - optimizations. + pre-Coppermine Celeron core. -config MPENTIUMIII +config CPU_PENTIUMIII bool "Pentium-III/Celeron(Coppermine)/Pentium-III Xeon" + default y help Select this for Intel chips based on the Pentium-III and - Celeron-Coppermine core. This option enables use of some - extended prefetch instructions in addition to the Pentium II - extensions. - -config MPENTIUM4 - bool "Pentium-4/Celeron(P4-based)/Xeon" - help - Select this for Intel Pentium 4 chips. This includes both - the Pentium 4 and P4-based Celeron chips. This option - enables compile flags optimized for the chip, uses the - correct cache shift, and applies any applicable Pentium III - optimizations. + Celeron-Coppermine core. + +config CPU_PENTIUMM + bool "Pentium M" + default y + help + Select this for Intel Pentium M (not Pentium-4 M) + notebook chips. + +config CPU_PENTIUM4 + bool "Pentium-4/Celeron(P4-based)/Pentium-4 M/Xeon" + default y + help + Select this for Intel Pentium 4 chips. This includes + the Pentium 4, P4-based Celeron and Xeon, and + Pentium-4 M (not Pentium M) chips. -config MK6 +config CPU_K6 bool "K6/K6-II/K6-III" + default y help - Select this for an AMD K6-family processor. Enables use of - some extended instructions, and passes appropriate optimization - flags to GCC. + Select this for an AMD K6, K6-II or K6-III (aka K6-3D). -config MK7 +config CPU_K7 bool "Athlon/Duron/K7" + default y help - Select this for an AMD Athlon K7-family processor. Enables use of - some extended instructions, and passes appropriate optimization - flags to GCC. + Select this for an AMD Athlon K7-family processor. -config MK8 +config CPU_K8 bool "Opteron/Athlon64/Hammer/K8" + default y help - Select this for an AMD Opteron or Athlon64 Hammer-family processor. Enables - use of some extended instructions, and passes appropriate optimization - flags to GCC. - -config MELAN - bool "Elan" + Select this for an AMD Opteron or Athlon64 Hammer-family processor. -config MCRUSOE +config CPU_CRUSOE bool "Crusoe" + default y help - Select this for a Transmeta Crusoe processor. Treats the processor - like a 586 with TSC, and sets some GCC optimization flags (like a - Pentium Pro with no alignment requirements). + Select this for a Transmeta Crusoe processor. -config MWINCHIPC6 +config CPU_WINCHIPC6 bool "Winchip-C6" + default y help - Select this for an IDT Winchip C6 chip. Linux and GCC - treat this chip as a 586TSC with some extended instructions - and alignment requirements. + Select this for an IDT Winchip C6 chip. -config MWINCHIP2 +config CPU_WINCHIP2 bool "Winchip-2" + default y help - Select this for an IDT Winchip-2. Linux and GCC - treat this chip as a 586TSC with some extended instructions - and alignment requirements. + Select this for an IDT Winchip-2. -config MWINCHIP3D +config CPU_WINCHIP3D bool "Winchip-2A/Winchip-3" + default y + help + Select this for an IDT Winchip-2A or 3 with 3dNow! + capabilities. + +config CPU_CYRIXIII + bool "Cyrix III/VIA C3" + default y help - Select this for an IDT Winchip-2A or 3. Linux and GCC - treat this chip as a 586TSC with some extended instructions - and alignment reqirements. Also enable out of order memory - stores for this CPU, which can increase performance of some - operations. - -config MCYRIXIII - bool "CyrixIII/VIA-C3" - help - Select this for a Cyrix III or C3 chip. Presently Linux and GCC - treat this chip as a generic 586. Whilst the CPU is 686 class, - it lacks the cmov extension which gcc assumes is present when - generating 686 code. - Note that Nehemiah (Model 9) and above will not boot with this - kernel due to them lacking the 3DNow! instructions used in earlier - incarnations of the CPU. + Select this for a Cyrix III or VIA C3 chip. + + Note that Nehemiah (Model 9) and above need the next + option instead. -config MVIAC3_2 +config CPU_VIAC3_2 bool "VIA C3-2 (Nehemiah)" + default y help - Select this for a VIA C3 "Nehemiah". Selecting this enables usage - of SSE and tells gcc to treat the CPU as a 686. - Note, this kernel will not boot on older (pre model 9) C3s. + Select this for a VIA C3 "Nehemiah" (model 9 and above). -endchoice +endmenu -config X86_GENERIC - bool "Generic x86 support" - help - Including some tuning for non selected x86 CPUs too. - when it has moderate overhead. This is intended for generic - distributions kernels. +endif + +# +# helper options +# +config CPU_INTEL + bool + depends on CPU_386 || CPU_486 || CPU_586TSC || CPU_686 || CPU_PENTIUMII || CPU_PENTIUMIII || CPU_PENTIUMM || CPU_PENTIUM4 + default y + +config CPU_WINCHIP + bool + depends on CPU_WINCHIPC6 || CPU_WINCHIP2 || CPU_WINCHIP3D + default y + +config CPU_ONLY_K7 + bool + depends on CPU_K7 && !CPU_INTEL && !CPU_K6 && !CPU_K8 && !X86_ELAN && !CPU_CRUSOE && !CPU_WINCHIP && !CPU_CYRIXIII && !CPU_VIAC3_2 + default y + +config CPU_ONLY_K8 + bool + depends on CPU_K8 && !CPU_INTEL && !CPU_K6 && !CPU_K7 && !X86_ELAN && !CPU_CRUSOE && !CPU_WINCHIP && !CPU_CYRIXIII && !CPU_VIAC3_2 + default y + +config CPU_ONLY_WINCHIP + bool + depends on CPU_WINCHIP && !CPU_INTEL && !CPU_K6 && !CPU_K7 && !CPU_K8 && !X86_ELAN && !CPU_CRUSOE && !CPU_CYRIXIII && !CPU_VIAC3_2 + default y # # Define implied options from the CPU selection here # config X86_CMPXCHG bool - depends on !M386 + depends on !CPU_386 default y config X86_XADD bool - depends on !M386 + depends on !CPU_386 default y config X86_L1_CACHE_SHIFT int - default "7" if MPENTIUM4 || X86_GENERIC - default "4" if MELAN || M486 || M386 - default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 - default "6" if MK7 || MK8 + default "7" if CPU_PENTIUM4 + default "6" if CPU_K7 || CPU_K8 || CPU_PENTIUMM + default "5" if CPU_WINCHIP || CPU_CRUSOE || CPU_CYRIXIII || CPU_K6 || CPU_PENTIUMIII || CPU_PENTIUMII || CPU_686 || CPU_586MMX || CPU_586TSC || CPU_586 || CPU_VIAC3_2 + default "4" if X86_ELAN || CPU_486 || CPU_386 config RWSEM_GENERIC_SPINLOCK bool - depends on M386 + depends on CPU_386 default y config RWSEM_XCHGADD_ALGORITHM bool - depends on !M386 + depends on !CPU_386 default y config X86_PPRO_FENCE bool - depends on M686 || M586MMX || M586TSC || M586 || M486 || M386 + depends on CPU_686 default y config X86_F00F_BUG bool - depends on M586MMX || M586TSC || M586 || M486 || M386 + depends on CPU_586MMX || CPU_586TSC default y config X86_WP_WORKS_OK bool - depends on !M386 + depends on !CPU_386 default y config X86_INVLPG bool - depends on !M386 + depends on !CPU_386 default y config X86_BSWAP bool - depends on !M386 + depends on !CPU_386 default y config X86_POPAD_OK bool - depends on !M386 + depends on !CPU_386 default y config X86_ALIGNMENT_16 bool - depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 + depends on CPU_WINCHIP || CPU_CYRIXIII || X86_ELAN || CPU_K6 || CPU_586MMX || CPU_586TSC || CPU_586 || CPU_486 || CPU_VIAC3_2 default y -config X86_GOOD_APIC +config X86_BAD_APIC bool - depends on MK7 || MPENTIUM4 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8 + depends on CPU_586TSC default y config X86_INTEL_USERCOPY bool - depends on MPENTIUM4 || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7 + depends on CPU_K7 || CPU_K8 || CPU_PENTIUMII || CPU_PENTIUMIII || CPU_PENTIUMM || CPU_PENTIUM4 default y config X86_USE_PPRO_CHECKSUM bool - depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 + depends on !CPU_386 && !CPU_486 && !CPU_586 && !CPU_586TSC && !CPU_586MMX && !X86_ELAN && !CPU_CRUSOE default y config X86_USE_3DNOW bool - depends on MCYRIXIII || MK7 + depends on !CPU_INTEL && !CPU_K6 && !CPU_K8 && !X86_ELAN && !CPU_CRUSOE && !CPU_WINCHIP && !CPU_VIAC3_2 default y config X86_OOSTORE bool - depends on (MWINCHIP3D || MWINCHIP2 || MWINCHIPC6) && MTRR + depends on CPU_ONLY_WINCHIP && MTRR default y +config X86_4G + bool "4 GB kernel-space and 4 GB user-space virtual memory support" + help + This option is only useful for systems that have more than 1 GB + of RAM. + + The default kernel VM layout leaves 1 GB of virtual memory for + kernel-space mappings, and 3 GB of VM for user-space applications. + This option ups both the kernel-space VM and the user-space VM to + 4 GB. + + The cost of this option is additional TLB flushes done at + system-entry points that transition from user-mode into kernel-mode. + I.e. system calls and page faults, and IRQs that interrupt user-mode + code. There's also additional overhead to kernel operations that copy + memory to/from user-space. The overhead from this is hard to tell and + depends on the workload - it can be anything from no visible overhead + to 20-30% overhead. A good rule of thumb is to count with a runtime + overhead of 20%. + + The upside is the much increased kernel-space VM, which more than + quadruples the maximum amount of RAM supported. Kernels compiled with + this option boot on 64GB of RAM and still have more than 3.1 GB of + 'lowmem' left. Another bonus is that highmem IO bouncing decreases, + if used with drivers that still use bounce-buffers. + + There's also a 33% increase in user-space VM size - database + applications might see a boost from this. + + But the cost of the TLB flushes and the runtime overhead has to be + weighed against the bonuses offered by the larger VM spaces. The + dividing line depends on the actual workload - there might be 4 GB + systems that benefit from this option. Systems with less than 4 GB + of RAM will rarely see a benefit from this option - but it's not + out of question, the exact circumstances have to be considered. + +config X86_SWITCH_PAGETABLES + def_bool X86_4G + +config X86_4G_VM_LAYOUT + def_bool X86_4G + +config X86_UACCESS_INDIRECT + def_bool X86_4G + +config X86_HIGH_ENTRY + def_bool X86_4G + config HPET_TIMER bool "HPET Timer Support" help @@ -459,6 +508,16 @@ This is purely to save memory - each supported CPU adds approximately eight kilobytes to the kernel image. +config SCHED_SMT + bool "SMT (Hyperthreading) scheduler support" + depends on SMP + default off + help + SMT scheduler support improves the CPU scheduler's decision making + when dealing with Intel Pentium 4 chips with HyperThreading at a + cost of slightly increased overhead in some places. If unsure say + N here. + config PREEMPT bool "Preemptible Kernel" help @@ -513,7 +572,7 @@ config X86_TSC bool - depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2) && !X86_NUMAQ + depends on !X86_NUMAQ && !CPU_386 && !CPU_486 && !CPU_586 && !X86_ELAN && !CPU_WINCHIPC6 default y config X86_MCE @@ -603,8 +662,6 @@ To compile this driver as a module, choose M here: the module will be called microcode. - If you use modprobe or kmod you may also want to add the line - 'alias char-major-10-184 microcode' to your /etc/modules.conf file. config X86_MSR tristate "/dev/cpu/*/msr - Model-specific register support" @@ -821,6 +878,19 @@ depends on (((X86_SUMMIT || X86_GENERICARCH) && NUMA) || (X86 && EFI)) default y +config REGPARM + bool "Use register arguments (EXPERIMENTAL)" + depends on EXPERIMENTAL + default n + help + Compile the kernel with -mregparm=3. This uses an different ABI + and passes the first three arguments of a function call in registers. + This will probably break binary only modules. + + This feature is only enabled for gcc-3.0 and later - earlier compilers + generate incorrect output with certain kernel constructs when + -mregparm=3 is used. + endmenu @@ -1030,12 +1100,16 @@ PCI-based systems don't have any BIOS at all. Linux can also try to detect the PCI hardware directly without using the BIOS. - With this option, you can specify how Linux should detect the PCI - devices. If you choose "BIOS", the BIOS will be used, if you choose - "Direct", the BIOS won't be used, and if you choose "Any", the - kernel will try the direct access method and falls back to the BIOS - if that doesn't work. If unsure, go with the default, which is - "Any". + With this option, you can specify how Linux should detect the + PCI devices. If you choose "BIOS", the BIOS will be used, + if you choose "Direct", the BIOS won't be used, and if you + choose "MMConfig", then PCI Express MMCONFIG will be used. + If you choose "Any", the kernel will try MMCONFIG, then the + direct access method and falls back to the BIOS if that doesn't + work. If unsure, go with the default, which is "Any". + +config PCI_GOMMCONFIG + bool "MMConfig" config PCI_GODIRECT bool "Direct" @@ -1055,6 +1129,12 @@ depends on PCI && ((PCI_GODIRECT || PCI_GOANY) || X86_VISWS) default y +config PCI_MMCONFIG + bool + depends on PCI && (PCI_GOMMCONFIG || PCI_GOANY) + select ACPI_BOOT + default y + config PCI_USE_VECTOR bool "Vector-based interrupt indexing" depends on X86_LOCAL_APIC && X86_IO_APIC @@ -1149,6 +1229,15 @@ agent" (/sbin/hotplug) to load modules and set up software needed to use devices as you hotplug them. +config HOTPLUG_CPU + bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" + depends on SMP && HOTPLUG && EXPERIMENTAL + ---help--- + Say Y here to experiment with turning CPUs off and on. CPUs + can be controlled through /sys/devices/system/cpu. + + Say N. + source "drivers/pcmcia/Kconfig" source "drivers/pci/hotplug/Kconfig" @@ -1231,6 +1320,15 @@ This results in a large slowdown, but helps to find certain types of memory corruptions. +config SPINLINE + bool "Spinlock inlining" + depends on DEBUG_KERNEL + help + This will change spinlocks from out of line to inline, making them + account cost to the callers in readprofile, rather than the lock + itself (as ".text.lock.filename"). This can be helpful for finding + the callers of locks. + config DEBUG_HIGHMEM bool "Highmem debugging" depends on DEBUG_KERNEL && HIGHMEM @@ -1247,20 +1345,208 @@ Say Y here only if you plan to use gdb to debug the kernel. If you don't debug the kernel, you can say N. +config LOCKMETER + bool "Kernel lock metering" + depends on SMP + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + config DEBUG_SPINLOCK_SLEEP bool "Sleep-inside-spinlock checking" help If you say Y here, various routines which may sleep will become very noisy if they are called with a spinlock held. +config KGDB + bool "Include kgdb kernel debugger" + depends on DEBUG_KERNEL + help + If you say Y here, the system will be compiled with the debug + option (-g) and a debugging stub will be included in the + kernel. This stub communicates with gdb on another (host) + computer via a serial port. The host computer should have + access to the kernel binary file (vmlinux) and a serial port + that is connected to the target machine. Gdb can be made to + configure the serial port or you can use stty and setserial to + do this. See the 'target' command in gdb. This option also + configures in the ability to request a breakpoint early in the + boot process. To request the breakpoint just include 'kgdb' + as a boot option when booting the target machine. The system + will then break as soon as it looks at the boot options. This + option also installs a breakpoint in panic and sends any + kernel faults to the debugger. For more information see the + Documentation/i386/kgdb/kgdb.txt file. + +choice + depends on KGDB + prompt "Debug serial port BAUD" + default KGDB_115200BAUD + help + Gdb and the kernel stub need to agree on the baud rate to be + used. Some systems (x86 family at this writing) allow this to + be configured. + +config KGDB_9600BAUD + bool "9600" + +config KGDB_19200BAUD + bool "19200" + +config KGDB_38400BAUD + bool "38400" + +config KGDB_57600BAUD + bool "57600" + +config KGDB_115200BAUD + bool "115200" +endchoice + +config KGDB_PORT + hex "hex I/O port address of the debug serial port" + depends on KGDB + default 3f8 + help + Some systems (x86 family at this writing) allow the port + address to be configured. The number entered is assumed to be + hex, don't put 0x in front of it. The standard address are: + COM1 3f8 , irq 4 and COM2 2f8 irq 3. Setserial /dev/ttySx + will tell you what you have. It is good to test the serial + connection with a live system before trying to debug. + +config KGDB_IRQ + int "IRQ of the debug serial port" + depends on KGDB + default 4 + help + This is the irq for the debug port. If everything is working + correctly and the kernel has interrupts on a control C to the + port should cause a break into the kernel debug stub. + +config DEBUG_INFO + bool + depends on KGDB + default y + +config KGDB_MORE + bool "Add any additional compile options" + depends on KGDB + default n + help + Saying yes here turns on the ability to enter additional + compile options. + + +config KGDB_OPTIONS + depends on KGDB_MORE + string "Additional compile arguments" + default "-O1" + help + This option allows you enter additional compile options for + the whole kernel compile. Each platform will have a default + that seems right for it. For example on PPC "-ggdb -O1", and + for i386 "-O1". Note that by configuring KGDB "-g" is already + turned on. In addition, on i386 platforms + "-fomit-frame-pointer" is deleted from the standard compile + options. + +config NO_KGDB_CPUS + int "Number of CPUs" + depends on KGDB && SMP + default NR_CPUS + help + + This option sets the number of cpus for kgdb ONLY. It is used + to prune some internal structures so they look "nice" when + displayed with gdb. This is to overcome possibly larger + numbers that may have been entered above. Enter the real + number to get nice clean kgdb_info displays. + +config KGDB_TS + bool "Enable kgdb time stamp macros?" + depends on KGDB + default n + help + Kgdb event macros allow you to instrument your code with calls + to the kgdb event recording function. The event log may be + examined with gdb at a break point. Turning on this + capability also allows you to choose how many events to + keep. Kgdb always keeps the lastest events. + +choice + depends on KGDB_TS + prompt "Max number of time stamps to save?" + default KGDB_TS_128 + +config KGDB_TS_64 + bool "64" + +config KGDB_TS_128 + bool "128" + +config KGDB_TS_256 + bool "256" + +config KGDB_TS_512 + bool "512" + +config KGDB_TS_1024 + bool "1024" + +endchoice + +config STACK_OVERFLOW_TEST + bool "Turn on kernel stack overflow testing?" + depends on KGDB + default n + help + This option enables code in the front line interrupt handlers + to check for kernel stack overflow on interrupts and system + calls. This is part of the kgdb code on x86 systems. + +config KGDB_CONSOLE + bool "Enable serial console thru kgdb port" + depends on KGDB + default n + help + This option enables the command line "console=kgdb" option. + When the system is booted with this option in the command line + all kernel printk output is sent to gdb (as well as to other + consoles). For this to work gdb must be connected. For this + reason, this command line option will generate a breakpoint if + gdb has not yet connected. After the gdb continue command is + given all pent up console output will be printed by gdb on the + host machine. Neither this option, nor KGDB require the + serial driver to be configured. + +config KGDB_SYSRQ + bool "Turn on SysRq 'G' command to do a break?" + depends on KGDB + default y + help + This option includes an option in the SysRq code that allows + you to enter SysRq G which generates a breakpoint to the KGDB + stub. This will work if the keyboard is alive and can + interrupt the system. Because of constraints on when the + serial port interrupt can be enabled, this code may allow you + to interrupt the system before the serial port control C is + available. Just say yes here. + config FRAME_POINTER bool "Compile the kernel with frame pointers" + default KGDB help If you say Y here the resulting kernel image will be slightly larger and slower, but it will give very useful debugging information. If you don't debug the kernel, you can say N, but we may not be able to solve problems without frame pointers. +config MAGIC_SYSRQ + bool + depends on KGDB_SYSRQ + default y + config X86_FIND_SMP_CONFIG bool depends on X86_LOCAL_APIC || X86_VOYAGER --- diff/arch/i386/Makefile 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/Makefile 2004-02-09 10:39:50.000000000 +0000 @@ -19,33 +19,63 @@ OBJCOPYFLAGS := -O binary -R .note -R .comment -S LDFLAGS_vmlinux := -CFLAGS += -pipe +CFLAGS += -pipe -msoft-float # prevent gcc from keeping the stack 16 byte aligned CFLAGS += $(call check_gcc,-mpreferred-stack-boundary=2,) align := $(subst -functions=0,,$(call check_gcc,-falign-functions=0,-malign-functions=0)) -cflags-$(CONFIG_M386) += -march=i386 -cflags-$(CONFIG_M486) += -march=i486 -cflags-$(CONFIG_M586) += -march=i586 -cflags-$(CONFIG_M586TSC) += -march=i586 -cflags-$(CONFIG_M586MMX) += $(call check_gcc,-march=pentium-mmx,-march=i586) -cflags-$(CONFIG_M686) += -march=i686 -cflags-$(CONFIG_MPENTIUMII) += $(call check_gcc,-march=pentium2,-march=i686) -cflags-$(CONFIG_MPENTIUMIII) += $(call check_gcc,-march=pentium3,-march=i686) -cflags-$(CONFIG_MPENTIUM4) += $(call check_gcc,-march=pentium4,-march=i686) -cflags-$(CONFIG_MK6) += $(call check_gcc,-march=k6,-march=i586) +cflags-$(CONFIG_CPU_PENTIUM4) := $(call check_gcc,-march=pentium4,-march=i686) + +ifdef CONFIG_CPU_PENTIUM4 + cflags-$(CONFIG_CPU_K8) := $(call check_gcc,-march=pentium3,-march=i686) +else + cflags-$(CONFIG_CPU_K8) := $(call check_gcc,-march=k8,$(call check_gcc,-march=athlon,-march=i686 $(align)-functions=4)) +endif + # Please note, that patches that add -march=athlon-xp and friends are pointless. # They make zero difference whatsosever to performance at this time. -cflags-$(CONFIG_MK7) += $(call check_gcc,-march=athlon,-march=i686 $(align)-functions=4) -cflags-$(CONFIG_MK8) += $(call check_gcc,-march=k8,$(call check_gcc,-march=athlon,-march=i686 $(align)-functions=4)) -cflags-$(CONFIG_MCRUSOE) += -march=i686 $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 -cflags-$(CONFIG_MWINCHIPC6) += $(call check_gcc,-march=winchip-c6,-march=i586) -cflags-$(CONFIG_MWINCHIP2) += $(call check_gcc,-march=winchip2,-march=i586) -cflags-$(CONFIG_MWINCHIP3D) += $(call check_gcc,-march=winchip2,-march=i586) -cflags-$(CONFIG_MCYRIXIII) += $(call check_gcc,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 -cflags-$(CONFIG_MVIAC3_2) += $(call check_gcc,-march=c3-2,-march=i686) +ifdef CONFIG_CPU_PENTIUM4 + cflags-$(CONFIG_CPU_K7) := $(call check_gcc,-march=pentium3,-march=i686) +else + cflags-$(CONFIG_CPU_K7) := $(call check_gcc,-march=athlon,-march=i686 $(align)-functions=4) +endif + +cflags-$(CONFIG_CPU_PENTIUMM) := $(call check_gcc,-march=pentium3,-march=i686) +cflags-$(CONFIG_CPU_PENTIUMIII) := $(call check_gcc,-march=pentium3,-march=i686) +cflags-$(CONFIG_CPU_PENTIUMII) := $(call check_gcc,-march=pentium2,-march=i686) +cflags-$(CONFIG_CPU_VIAC3_2) := $(call check_gcc,-march=c3-2,-march=i686) +cflags-$(CONFIG_CPU_CRUSOE) := -march=i686 $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 +cflags-$(CONFIG_CPU_686) := -march=i686 + +# supports i686 without cmov +cflags-$(CONFIG_CPU_CYRIXIII) := $(call check_gcc,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 + +cflags-$(CONFIG_CPU_K6) := -march=k6 +cflags-$(CONFIG_CPU_586MMX) := $(call check_gcc,-march=pentium-mmx,-march=i586) + +# Winchip supports i586 +cflags-$(CONFIG_CPU_WINCHIPC6) := $(call check_gcc,-march=winchip-c6,-march=i486) +cflags-$(CONFIG_CPU_WINCHIP2) := $(call check_gcc,-march=winchip2,-march=i486) +cflags-$(CONFIG_CPU_WINCHIP3D) := $(call check_gcc,-march=winchip2,-march=i486) + +cflags-$(CONFIG_CPU_586TSC) := -march=i586 +cflags-$(CONFIG_CPU_586) := -march=i586 +cflags-$(CONFIG_CPU_486) := -march=i486 +cflags-$(CONFIG_CPU_386) := -march=i386 + +# AMD Elan support +cflags-$(CONFIG_X86_ELAN) := -march=i486 + +# -mregparm=3 works ok on gcc-3.0 and later +# +GCC_VERSION := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) +cflags-$(CONFIG_REGPARM) += $(shell if [ $(GCC_VERSION) -ge 0300 ] ; then echo "-mregparm=3"; fi ;) + +# Enable unit-at-a-time mode when possible. It shrinks the +# kernel considerably. +CFLAGS += $(call check_gcc,-funit-at-a-time,) CFLAGS += $(cflags-y) @@ -84,6 +114,9 @@ # default subarch .h files mflags-y += -Iinclude/asm-i386/mach-default +mflags-$(CONFIG_KGDB) += -gdwarf-2 +mflags-$(CONFIG_KGDB_MORE) += $(shell echo $(CONFIG_KGDB_OPTIONS) | sed -e 's/"//g') + head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task.o libs-y += arch/i386/lib/ --- diff/arch/i386/boot/compressed/misc.c 2003-09-30 15:46:11.000000000 +0100 +++ source/arch/i386/boot/compressed/misc.c 2004-02-09 10:39:50.000000000 +0000 @@ -104,7 +104,7 @@ static void *malloc(int size); static void free(void *where); -static void puts(const char *); +static void putstr(const char *); extern int end; static long free_mem_ptr = (long)&end; @@ -169,7 +169,7 @@ vidmem[i] = ' '; } -static void puts(const char *s) +static void putstr(const char *s) { int x,y,pos; char c; @@ -287,9 +287,9 @@ static void error(char *x) { - puts("\n\n"); - puts(x); - puts("\n\n -- System halted"); + putstr("\n\n"); + putstr(x); + putstr("\n\n -- System halted"); while(1); /* Halt */ } @@ -373,9 +373,9 @@ else setup_output_buffer_if_we_run_high(mv); makecrc(); - puts("Uncompressing Linux... "); + putstr("Uncompressing Linux... "); gunzip(); - puts("Ok, booting the kernel.\n"); + putstr("Ok, booting the kernel.\n"); if (high_loaded) close_output_buffer_if_we_run_high(mv); return high_loaded; } --- diff/arch/i386/boot/setup.S 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/i386/boot/setup.S 2004-02-09 10:39:50.000000000 +0000 @@ -49,6 +49,8 @@ * by Matt Domsch October 2002 * conformant to T13 Committee www.t13.org * projects 1572D, 1484D, 1386D, 1226DT + * disk signature read by Matt Domsch + * and Andrew Wilks September 2003 */ #include @@ -162,7 +164,7 @@ # can be located anywhere in # low memory 0x10000 or higher. -ramdisk_max: .long MAXMEM-1 # (Header version 0x0203 or later) +ramdisk_max: .long __MAXMEM-1 # (Header version 0x0203 or later) # The highest safe address for # the contents of an initrd @@ -578,6 +580,25 @@ #endif #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) +# Read the first sector of device 80h and store the 4-byte signature + movl $0xFFFFFFFF, %eax + movl %eax, (DISK80_SIG_BUFFER) # assume failure + movb $READ_SECTORS, %ah + movb $1, %al # read 1 sector + movb $0x80, %dl # from device 80 + movb $0, %dh # at head 0 + movw $1, %cx # cylinder 0, sector 0 + pushw %es + pushw %ds + popw %es + movw $EDDBUF, %bx + int $0x13 + jc disk_sig_done + movl (EDDBUF+MBR_SIG_OFFSET), %eax + movl %eax, (DISK80_SIG_BUFFER) # store success +disk_sig_done: + popw %es + # Do the BIOS Enhanced Disk Drive calls # This consists of two calls: # int 13h ah=41h "Check Extensions Present" @@ -755,7 +776,7 @@ # AMD Elan bug fix by Robert Schwebel. # -#if defined(CONFIG_MELAN) +#if defined(CONFIG_X86_ELAN) movb $0x02, %al # alternate A20 gate outb %al, $0x92 # this works on SC410/SC520 a20_elan_wait: --- diff/arch/i386/kernel/Makefile 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/i386/kernel/Makefile 2004-02-09 10:39:50.000000000 +0000 @@ -7,13 +7,14 @@ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \ - doublefault.o + doublefault.o entry_trampoline.o obj-y += cpu/ obj-y += timers/ obj-$(CONFIG_ACPI_BOOT) += acpi/ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o obj-$(CONFIG_MCA) += mca.o +obj-$(CONFIG_KGDB) += kgdb_stub.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o --- diff/arch/i386/kernel/acpi/boot.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/i386/kernel/acpi/boot.c 2004-02-09 10:39:50.000000000 +0000 @@ -27,11 +27,14 @@ #include #include #include +#include #include #include #include #include +#include #include +#include #if defined (CONFIG_X86_LOCAL_APIC) #include @@ -44,8 +47,8 @@ int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ int acpi_ht __initdata = 1; /* enable HT */ -int acpi_lapic = 0; -int acpi_ioapic = 0; +int acpi_lapic; +int acpi_ioapic; /* -------------------------------------------------------------------------- Boot-time Configuration @@ -94,6 +97,27 @@ } +#ifdef CONFIG_PCI_MMCONFIG +static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) +{ + struct acpi_table_mcfg *mcfg; + + if (!phys_addr || !size) + return -EINVAL; + + mcfg = (struct acpi_table_mcfg *) __acpi_map_table(phys_addr, size); + if (!mcfg) { + printk(KERN_WARNING PREFIX "Unable to map MCFG\n"); + return -ENODEV; + } + + if (mcfg->base_address) + pci_mmcfg_base_addr = mcfg->base_address; + + return 0; +} +#endif /* CONFIG_PCI_MMCONFIG */ + #ifdef CONFIG_X86_LOCAL_APIC static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; @@ -311,7 +335,14 @@ #endif /* CONFIG_ACPI_BUS */ - +#ifdef CONFIG_X86_IO_APIC +int acpi_irq_to_vector(u32 irq) +{ + if (use_pci_vector() && !platform_legacy_irq(irq)) + irq = IO_APIC_VECTOR(irq); + return irq; +} +#endif static unsigned long __init acpi_scan_rsdp ( @@ -326,7 +357,7 @@ * RSDP signature. */ for (offset = 0; offset < length; offset += 16) { - if (strncmp((char *) (start + offset), "RSD PTR ", sig_len)) + if (strncmp((char *) __va(start + offset), "RSD PTR ", sig_len)) continue; return (start + offset); } @@ -363,6 +394,37 @@ } #endif +/* detect the location of the ACPI PM Timer */ +#ifdef CONFIG_X86_PM_TIMER +extern u32 pmtmr_ioport; + +static int __init acpi_parse_fadt(unsigned long phys, unsigned long size) +{ + struct fadt_descriptor_rev2 *fadt =0; + + fadt = (struct fadt_descriptor_rev2*) __acpi_map_table(phys,size); + if(!fadt) { + printk(KERN_WARNING PREFIX "Unable to map FADT\n"); + return 0; + } + + if (fadt->revision >= FADT2_REVISION_ID) { + /* FADT rev. 2 */ + if (fadt->xpm_tmr_blk.address_space_id != ACPI_ADR_SPACE_SYSTEM_IO) + return 0; + + pmtmr_ioport = fadt->xpm_tmr_blk.address; + } else { + /* FADT rev. 1 */ + pmtmr_ioport = fadt->V1_pm_tmr_blk; + } + if (pmtmr_ioport) + printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", pmtmr_ioport); + return 0; +} +#endif + + unsigned long __init acpi_find_rsdp (void) { @@ -435,6 +497,10 @@ return result; } +#ifdef CONFIG_X86_PM_TIMER + acpi_table_parse(ACPI_FADT, acpi_parse_fadt); +#endif + #ifdef CONFIG_X86_LOCAL_APIC /* @@ -463,7 +529,7 @@ * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). */ - result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr); + result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); return result; @@ -471,7 +537,8 @@ mp_register_lapic_address(acpi_lapic_addr); - result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic); + result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic, + MAX_APICS); if (!result) { printk(KERN_ERR PREFIX "No LAPIC entries present\n"); /* TBD: Cleanup to allow fallback to MPS */ @@ -483,7 +550,7 @@ return result; } - result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi); + result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); /* TBD: Cleanup to allow fallback to MPS */ @@ -520,8 +587,8 @@ return 1; } - result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic); - if (!result) { + result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic, MAX_IO_APICS); + if (!result) { printk(KERN_ERR PREFIX "No IOAPIC entries present\n"); return -ENODEV; } @@ -533,14 +600,14 @@ /* Build a default routing table for legacy (ISA) interrupts. */ mp_config_acpi_legacy_irqs(); - result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr); + result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, NR_IRQ_VECTORS); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); /* TBD: Cleanup to allow fallback to MPS */ return result; } - result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src); + result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, NR_IRQ_VECTORS); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); /* TBD: Cleanup to allow fallback to MPS */ @@ -555,6 +622,19 @@ #endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */ +#ifdef CONFIG_PCI_MMCONFIG + result = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); + if (!result) { + printk(KERN_WARNING PREFIX "MCFG not present\n"); + return 0; + } else if (result < 0) { + printk(KERN_ERR PREFIX "Error parsing MCFG\n"); + return result; + } else if (result > 1) { + printk(KERN_WARNING PREFIX "Multiple MCFG tables exist\n"); + } +#endif /* CONFIG_PCI_MMCONFIG */ + #ifdef CONFIG_X86_LOCAL_APIC if (acpi_lapic && acpi_ioapic) { smp_found_config = 1; --- diff/arch/i386/kernel/asm-offsets.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/kernel/asm-offsets.c 2004-02-09 10:39:50.000000000 +0000 @@ -4,9 +4,11 @@ * to extract and format the required data. */ +#include #include #include #include "sigframe.h" +#include #define DEFINE(sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) @@ -28,4 +30,17 @@ DEFINE(RT_SIGFRAME_sigcontext, offsetof (struct rt_sigframe, uc.uc_mcontext)); + DEFINE(TI_task, offsetof (struct thread_info, task)); + DEFINE(TI_exec_domain, offsetof (struct thread_info, exec_domain)); + DEFINE(TI_flags, offsetof (struct thread_info, flags)); + DEFINE(TI_preempt_count, offsetof (struct thread_info, preempt_count)); + DEFINE(TI_addr_limit, offsetof (struct thread_info, addr_limit)); + DEFINE(TI_real_stack, offsetof (struct thread_info, real_stack)); + DEFINE(TI_virtual_stack, offsetof (struct thread_info, virtual_stack)); + DEFINE(TI_user_pgd, offsetof (struct thread_info, user_pgd)); + + DEFINE(FIX_ENTRY_TRAMPOLINE_0_addr, __fix_to_virt(FIX_ENTRY_TRAMPOLINE_0)); + DEFINE(FIX_VSYSCALL_addr, __fix_to_virt(FIX_VSYSCALL)); + DEFINE(PAGE_SIZE_asm, PAGE_SIZE); + DEFINE(task_thread_db7, offsetof (struct task_struct, thread.debugreg[7])); } --- diff/arch/i386/kernel/cpu/centaur.c 2003-05-21 11:49:49.000000000 +0100 +++ source/arch/i386/kernel/cpu/centaur.c 2004-02-09 10:39:50.000000000 +0000 @@ -246,7 +246,15 @@ lo&=~0x1C0; /* blank bits 8-6 */ wrmsr(MSR_IDT_MCR_CTRL, lo, hi); } -#endif +#endif /* CONFIG_X86_OOSTORE */ + +#define ACE_PRESENT (1 << 6) +#define ACE_ENABLED (1 << 7) +#define ACE_FCR (1 << 28) /* MSR_VIA_FCR */ + +#define RNG_PRESENT (1 << 2) +#define RNG_ENABLED (1 << 3) +#define RNG_ENABLE (1 << 6) /* MSR_VIA_RNG */ static void __init init_c3(struct cpuinfo_x86 *c) { @@ -254,6 +262,24 @@ /* Test for Centaur Extended Feature Flags presence */ if (cpuid_eax(0xC0000000) >= 0xC0000001) { + u32 tmp = cpuid_edx(0xC0000001); + + /* enable ACE unit, if present and disabled */ + if ((tmp & (ACE_PRESENT | ACE_ENABLED)) == ACE_PRESENT) { + rdmsr (MSR_VIA_FCR, lo, hi); + lo |= ACE_FCR; /* enable ACE unit */ + wrmsr (MSR_VIA_FCR, lo, hi); + printk(KERN_INFO "CPU: Enabled ACE h/w crypto\n"); + } + + /* enable RNG unit, if present and disabled */ + if ((tmp & (RNG_PRESENT | RNG_ENABLED)) == RNG_PRESENT) { + rdmsr (MSR_VIA_RNG, lo, hi); + lo |= RNG_ENABLE; /* enable RNG unit */ + wrmsr (MSR_VIA_RNG, lo, hi); + printk(KERN_INFO "CPU: Enabled h/w RNG\n"); + } + /* store Centaur Extended Feature Flags as * word 5 of the CPU capability bit array */ --- diff/arch/i386/kernel/cpu/common.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/i386/kernel/cpu/common.c 2004-02-09 10:39:50.000000000 +0000 @@ -514,12 +514,16 @@ set_tss_desc(cpu,t); cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; load_TR_desc(); - load_LDT(&init_mm.context); + if (cpu) + load_LDT(&init_mm.context); /* Set up doublefault TSS pointer in the GDT */ __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); cpu_gdt_table[cpu][GDT_ENTRY_DOUBLEFAULT_TSS].b &= 0xfffffdff; + if (cpu) + trap_init_virtual_GDT(); + /* Clear %fs and %gs. */ asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); --- diff/arch/i386/kernel/cpu/cpufreq/Kconfig 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/i386/kernel/cpu/cpufreq/Kconfig 2004-02-09 10:39:50.000000000 +0000 @@ -54,7 +54,7 @@ config ELAN_CPUFREQ tristate "AMD Elan" - depends on CPU_FREQ_TABLE && MELAN + depends on CPU_FREQ_TABLE && X86_ELAN ---help--- This adds the CPUFreq driver for AMD Elan SC400 and SC410 processors. --- diff/arch/i386/kernel/cpu/cpufreq/acpi.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/i386/kernel/cpu/cpufreq/acpi.c 2004-02-09 10:39:50.000000000 +0000 @@ -1,9 +1,9 @@ /* - * acpi_processor_perf.c - ACPI Processor P-States Driver ($Revision: 1.3 $) + * acpi-cpufreq-io.c - ACPI Processor P-States Driver ($Revision: 1.3 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh - * Copyright (C) 2002, 2003 Dominik Brodowski + * Copyright (C) 2002 - 2004 Dominik Brodowski * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -42,7 +42,6 @@ #define ACPI_PROCESSOR_CLASS "processor" #define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor P-States Driver" #define ACPI_PROCESSOR_DEVICE_NAME "Processor" -#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME ("acpi_processor_perf") @@ -52,184 +51,13 @@ MODULE_LICENSE("GPL"); -static struct acpi_processor_performance *performance; - - -static int -acpi_processor_get_performance_control ( - struct acpi_processor_performance *perf) -{ - int result = 0; - acpi_status status = 0; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - union acpi_object *pct = NULL; - union acpi_object obj = {0}; - struct acpi_pct_register *reg = NULL; - - ACPI_FUNCTION_TRACE("acpi_processor_get_performance_control"); - - status = acpi_evaluate_object(perf->pr->handle, "_PCT", NULL, &buffer); - if(ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PCT\n")); - return_VALUE(-ENODEV); - } - - pct = (union acpi_object *) buffer.pointer; - if (!pct || (pct->type != ACPI_TYPE_PACKAGE) - || (pct->package.count != 2)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PCT data\n")); - result = -EFAULT; - goto end; - } - - /* - * control_register - */ - - obj = pct->package.elements[0]; - - if ((obj.type != ACPI_TYPE_BUFFER) - || (obj.buffer.length < sizeof(struct acpi_pct_register)) - || (obj.buffer.pointer == NULL)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Invalid _PCT data (control_register)\n")); - result = -EFAULT; - goto end; - } - - reg = (struct acpi_pct_register *) (obj.buffer.pointer); - - if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unsupported address space [%d] (control_register)\n", - (u32) reg->space_id)); - result = -EFAULT; - goto end; - } - - perf->control_register = (u16) reg->address; - perf->control_register_bit_width = reg->bit_width; - /* - * status_register - */ - - obj = pct->package.elements[1]; - - if ((obj.type != ACPI_TYPE_BUFFER) - || (obj.buffer.length < sizeof(struct acpi_pct_register)) - || (obj.buffer.pointer == NULL)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Invalid _PCT data (status_register)\n")); - result = -EFAULT; - goto end; - } - - reg = (struct acpi_pct_register *) (obj.buffer.pointer); - - if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unsupported address space [%d] (status_register)\n", - (u32) reg->space_id)); - result = -EFAULT; - goto end; - } - - perf->status_register = (u16) reg->address; - perf->status_register_bit_width = reg->bit_width; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "control_register[0x%04x] status_register[0x%04x]\n", - perf->control_register, - perf->status_register)); - -end: - acpi_os_free(buffer.pointer); - - return_VALUE(result); -} - - -static int -acpi_processor_get_performance_states ( - struct acpi_processor_performance * perf) -{ - int result = 0; - acpi_status status = AE_OK; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - struct acpi_buffer format = {sizeof("NNNNNN"), "NNNNNN"}; - struct acpi_buffer state = {0, NULL}; - union acpi_object *pss = NULL; - int i = 0; - - ACPI_FUNCTION_TRACE("acpi_processor_get_performance_states"); - - status = acpi_evaluate_object(perf->pr->handle, "_PSS", NULL, &buffer); - if(ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PSS\n")); - return_VALUE(-ENODEV); - } - - pss = (union acpi_object *) buffer.pointer; - if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n")); - result = -EFAULT; - goto end; - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states\n", - pss->package.count)); - - if (pss->package.count > ACPI_PROCESSOR_MAX_PERFORMANCE) { - perf->state_count = ACPI_PROCESSOR_MAX_PERFORMANCE; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Limiting number of states to max (%d)\n", - ACPI_PROCESSOR_MAX_PERFORMANCE)); - } - else - perf->state_count = pss->package.count; - - if (perf->state_count > 1) - perf->pr->flags.performance = 1; - - for (i = 0; i < perf->state_count; i++) { - - struct acpi_processor_px *px = &(perf->states[i]); - - state.length = sizeof(struct acpi_processor_px); - state.pointer = px; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i)); - - status = acpi_extract_package(&(pss->package.elements[i]), - &format, &state); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n")); - result = -EFAULT; - goto end; - } - - if (!px->core_frequency) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data: freq is zero\n")); - result = -EFAULT; - goto end; - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]\n", - i, - (u32) px->core_frequency, - (u32) px->power, - (u32) px->transition_latency, - (u32) px->bus_master_latency, - (u32) px->control, - (u32) px->status)); - } +struct cpufreq_acpi_io { + struct acpi_processor_performance acpi_data; + struct cpufreq_frequency_table *freq_table; +}; -end: - acpi_os_free(buffer.pointer); +static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS]; - return_VALUE(result); -} static int acpi_processor_write_port( @@ -270,7 +98,8 @@ static int acpi_processor_set_performance ( - struct acpi_processor_performance *perf, + struct cpufreq_acpi_io *data, + unsigned int cpu, int state) { u16 port = 0; @@ -282,38 +111,19 @@ ACPI_FUNCTION_TRACE("acpi_processor_set_performance"); - if (!perf || !perf->pr) - return_VALUE(-EINVAL); - - if (!perf->pr->flags.performance) - return_VALUE(-ENODEV); - - if (state >= perf->state_count) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, - "Invalid target state (P%d)\n", state)); - return_VALUE(-ENODEV); - } - - if (state < perf->pr->performance_platform_limit) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, - "Platform limit (P%d) overrides target state (P%d)\n", - perf->pr->performance_platform_limit, state)); - return_VALUE(-ENODEV); - } - - if (state == perf->state) { + if (state == data->acpi_data.state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Already at target state (P%d)\n", state)); return_VALUE(0); } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Transitioning from P%d to P%d\n", - perf->state, state)); + data->acpi_data.state, state)); /* cpufreq frequency struct */ - cpufreq_freqs.cpu = perf->pr->id; - cpufreq_freqs.old = perf->states[perf->state].core_frequency; - cpufreq_freqs.new = perf->states[state].core_frequency; + cpufreq_freqs.cpu = cpu; + cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency; + cpufreq_freqs.new = data->freq_table[state].frequency; /* notify cpufreq */ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE); @@ -323,9 +133,9 @@ * control_register. */ - port = perf->control_register; - bit_width = perf->control_register_bit_width; - value = (u32) perf->states[state].control; + port = data->acpi_data.control_register.address; + bit_width = data->acpi_data.control_register.bit_width; + value = (u32) data->acpi_data.states[state].control; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Writing 0x%08x to port 0x%04x\n", value, port)); @@ -344,12 +154,12 @@ * giving up. */ - port = perf->status_register; - bit_width = perf->status_register_bit_width; + port = data->acpi_data.status_register.address; + bit_width = data->acpi_data.status_register.bit_width; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Looking for 0x%08x from port 0x%04x\n", - (u32) perf->states[state].status, port)); + (u32) data->acpi_data.states[state].status, port)); for (i=0; i<100; i++) { ret = acpi_processor_read_port(port, bit_width, &value); @@ -358,7 +168,7 @@ "Invalid port width 0x%04x\n", bit_width)); return_VALUE(ret); } - if (value == (u32) perf->states[state].status) + if (value == (u32) data->acpi_data.states[state].status) break; udelay(10); } @@ -366,7 +176,7 @@ /* notify cpufreq */ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); - if (value != (u32) perf->states[state].status) { + if (value != (u32) data->acpi_data.states[state].status) { unsigned int tmp = cpufreq_freqs.new; cpufreq_freqs.new = cpufreq_freqs.old; cpufreq_freqs.old = tmp; @@ -380,169 +190,33 @@ "Transition successful after %d microseconds\n", i * 10)); - perf->state = state; + data->acpi_data.state = state; return_VALUE(0); } -#ifdef CONFIG_X86_ACPI_CPUFREQ_PROC_INTF -/* /proc/acpi/processor/../performance interface (DEPRECATED) */ - -static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file); -static struct file_operations acpi_processor_perf_fops = { - .open = acpi_processor_perf_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int acpi_processor_perf_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_processor *pr = (struct acpi_processor *)seq->private; - int i = 0; - - ACPI_FUNCTION_TRACE("acpi_processor_perf_seq_show"); - - if (!pr) - goto end; - - if (!pr->flags.performance || !pr->performance) { - seq_puts(seq, "\n"); - goto end; - } - - seq_printf(seq, "state count: %d\n" - "active state: P%d\n", - pr->performance->state_count, - pr->performance->state); - - seq_puts(seq, "states:\n"); - for (i = 0; i < pr->performance->state_count; i++) - seq_printf(seq, " %cP%d: %d MHz, %d mW, %d uS\n", - (i == pr->performance->state?'*':' '), i, - (u32) pr->performance->states[i].core_frequency, - (u32) pr->performance->states[i].power, - (u32) pr->performance->states[i].transition_latency); - -end: - return 0; -} - -static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_processor_perf_seq_show, - PDE(inode)->data); -} - -static int -acpi_processor_write_performance ( - struct file *file, - const char __user *buffer, - size_t count, - loff_t *data) -{ - int result = 0; - struct acpi_processor *pr = (struct acpi_processor *) data; - char state_string[12] = {'\0'}; - unsigned int new_state = 0; - struct cpufreq_policy policy; - - ACPI_FUNCTION_TRACE("acpi_processor_write_performance"); - - if (!pr || !pr->performance || (count > sizeof(state_string) - 1)) - return_VALUE(-EINVAL); - - if (copy_from_user(state_string, buffer, count)) - return_VALUE(-EFAULT); - - state_string[count] = '\0'; - new_state = simple_strtoul(state_string, NULL, 0); - - cpufreq_get_policy(&policy, pr->id); - - policy.cpu = pr->id; - policy.max = pr->performance->states[new_state].core_frequency * 1000; - - result = cpufreq_set_policy(&policy); - if (result) - return_VALUE(result); - - return_VALUE(count); -} - -static void -acpi_cpufreq_add_file ( - struct acpi_processor *pr) -{ - struct proc_dir_entry *entry = NULL; - struct acpi_device *device = NULL; - - ACPI_FUNCTION_TRACE("acpi_cpufreq_addfile"); - - if (acpi_bus_get_device(pr->handle, &device)) - return_VOID; - - /* add file 'performance' [R/W] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE, - S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); - if (!entry) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to create '%s' fs entry\n", - ACPI_PROCESSOR_FILE_PERFORMANCE)); - else { - entry->proc_fops = &acpi_processor_perf_fops; - entry->proc_fops->write = acpi_processor_write_performance; - entry->data = acpi_driver_data(device); - } - return_VOID; -} - -static void -acpi_cpufreq_remove_file ( - struct acpi_processor *pr) -{ - struct acpi_device *device = NULL; - - ACPI_FUNCTION_TRACE("acpi_cpufreq_addfile"); - - if (acpi_bus_get_device(pr->handle, &device)) - return_VOID; - - /* remove file 'performance' */ - remove_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE, - acpi_device_dir(device)); - - return_VOID; -} - -#else -static void acpi_cpufreq_add_file (struct acpi_processor *pr) { return; } -static void acpi_cpufreq_remove_file (struct acpi_processor *pr) { return; } -#endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */ - - static int acpi_cpufreq_target ( struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { - struct acpi_processor_performance *perf = &performance[policy->cpu]; + struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; unsigned int next_state = 0; unsigned int result = 0; ACPI_FUNCTION_TRACE("acpi_cpufreq_setpolicy"); - result = cpufreq_frequency_table_target(policy, - &perf->freq_table[perf->pr->limit.state.px], + result = cpufreq_frequency_table_target(policy, + data->freq_table, target_freq, relation, &next_state); if (result) return_VALUE(result); - result = acpi_processor_set_performance (perf, next_state); + result = acpi_processor_set_performance (data, policy->cpu, next_state); return_VALUE(result); } @@ -553,119 +227,110 @@ struct cpufreq_policy *policy) { unsigned int result = 0; - struct acpi_processor_performance *perf = &performance[policy->cpu]; + struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; ACPI_FUNCTION_TRACE("acpi_cpufreq_verify"); result = cpufreq_frequency_table_verify(policy, - &perf->freq_table[perf->pr->limit.state.px]); - - cpufreq_verify_within_limits( - policy, - perf->states[perf->state_count - 1].core_frequency * 1000, - perf->states[perf->pr->limit.state.px].core_frequency * 1000); + data->freq_table); return_VALUE(result); } static int -acpi_processor_get_performance_info ( - struct acpi_processor_performance *perf) -{ - int result = 0; - acpi_status status = AE_OK; - acpi_handle handle = NULL; - - ACPI_FUNCTION_TRACE("acpi_processor_get_performance_info"); - - if (!perf || !perf->pr || !perf->pr->handle) - return_VALUE(-EINVAL); - - status = acpi_get_handle(perf->pr->handle, "_PCT", &handle); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "ACPI-based processor performance control unavailable\n")); - return_VALUE(-ENODEV); - } - - result = acpi_processor_get_performance_control(perf); - if (result) - return_VALUE(result); - - result = acpi_processor_get_performance_states(perf); - if (result) - return_VALUE(result); - - result = acpi_processor_get_platform_limit(perf->pr); - if (result) - return_VALUE(result); - - return_VALUE(0); -} - - -static int acpi_cpufreq_cpu_init ( struct cpufreq_policy *policy) { unsigned int i; unsigned int cpu = policy->cpu; - struct acpi_processor *pr = NULL; - struct acpi_processor_performance *perf = &performance[policy->cpu]; - struct acpi_device *device; + struct cpufreq_acpi_io *data; unsigned int result = 0; ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_init"); - acpi_processor_register_performance(perf, &pr, cpu); + data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); + if (!data) + return_VALUE(-ENOMEM); + memset(data, 0, sizeof(struct cpufreq_acpi_io)); - pr = performance[cpu].pr; - if (!pr) - return_VALUE(-ENODEV); + acpi_io_data[cpu] = data; - result = acpi_processor_get_performance_info(perf); + result = acpi_processor_register_performance(&data->acpi_data, cpu); if (result) - return_VALUE(-ENODEV); + goto err_free; /* capability check */ - if (!pr->flags.performance) - return_VALUE(-ENODEV); + if (data->acpi_data.state_count <= 1) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No P-States\n")); + result = -ENODEV; + goto err_unreg; + } + if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) || + (data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unsupported address space [%d, %d]\n", + (u32) (data->acpi_data.control_register.space_id), + (u32) (data->acpi_data.status_register.space_id))); + result = -ENODEV; + goto err_unreg; + } + + /* alloc freq_table */ + data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (data->acpi_data.state_count + 1), GFP_KERNEL); + if (!data->freq_table) { + result = -ENOMEM; + goto err_unreg; + } /* detect transition latency */ policy->cpuinfo.transition_latency = 0; - for (i=0;istate_count;i++) { - if ((perf->states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency) - policy->cpuinfo.transition_latency = perf->states[i].transition_latency * 1000; + for (i=0; iacpi_data.state_count; i++) { + if ((data->acpi_data.states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency) + policy->cpuinfo.transition_latency = data->acpi_data.states[i].transition_latency * 1000; } policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cur = perf->states[pr->limit.state.px].core_frequency * 1000; + + /* + * The current speed is unknown and not detectable by ACPI... argh! Assume + * it's P0, it will be set to this value later during initialization. + */ + policy->cur = data->acpi_data.states[0].core_frequency * 1000; /* table init */ - for (i=0; i<=perf->state_count; i++) + for (i=0; i<=data->acpi_data.state_count; i++) { - perf->freq_table[i].index = i; - if (istate_count) - perf->freq_table[i].frequency = perf->states[i].core_frequency * 1000; + data->freq_table[i].index = i; + if (iacpi_data.state_count) + data->freq_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000; else - perf->freq_table[i].frequency = CPUFREQ_TABLE_END; + data->freq_table[i].frequency = CPUFREQ_TABLE_END; } - result = cpufreq_frequency_table_cpuinfo(policy, &perf->freq_table[0]); - - acpi_cpufreq_add_file(pr); - - if (acpi_bus_get_device(pr->handle, &device)) - device = NULL; + result = cpufreq_frequency_table_cpuinfo(policy, &data->freq_table[0]); + if (result) { + goto err_freqfree; + } - printk(KERN_INFO "cpufreq: %s - ACPI performance management activated.\n", - device ? acpi_device_bid(device) : "CPU??"); - for (i = 0; i < pr->performance->state_count; i++) + + printk(KERN_INFO "cpufreq: CPU%u - ACPI performance management activated.\n", + cpu); + for (i = 0; i < data->acpi_data.state_count; i++) printk(KERN_INFO "cpufreq: %cP%d: %d MHz, %d mW, %d uS\n", - (i == pr->performance->state?'*':' '), i, - (u32) pr->performance->states[i].core_frequency, - (u32) pr->performance->states[i].power, - (u32) pr->performance->states[i].transition_latency); + (i == data->acpi_data.state?'*':' '), i, + (u32) data->acpi_data.states[i].core_frequency, + (u32) data->acpi_data.states[i].power, + (u32) data->acpi_data.states[i].transition_latency); + + return_VALUE(result); + + err_freqfree: + kfree(data->freq_table); + err_unreg: + acpi_processor_unregister_performance(&data->acpi_data, cpu); + err_free: + kfree(data); + acpi_io_data[cpu] = NULL; + return_VALUE(result); } @@ -674,11 +339,16 @@ acpi_cpufreq_cpu_exit ( struct cpufreq_policy *policy) { - struct acpi_processor *pr = performance[policy->cpu].pr; + struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; + ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_exit"); - acpi_cpufreq_remove_file(pr); + if (data) { + acpi_io_data[policy->cpu] = NULL; + acpi_processor_unregister_performance(&data->acpi_data, policy->cpu); + kfree(data); + } return_VALUE(0); } @@ -698,97 +368,11 @@ acpi_cpufreq_init (void) { int result = 0; - int current_state = 0; - int i = 0; - struct acpi_processor *pr = NULL; - struct acpi_processor_performance *perf = NULL; ACPI_FUNCTION_TRACE("acpi_cpufreq_init"); - /* alloc memory */ - if (performance) - return_VALUE(-EBUSY); - - performance = kmalloc(NR_CPUS * sizeof(struct acpi_processor_performance), GFP_KERNEL); - if (!performance) - return_VALUE(-ENOMEM); - memset(performance, 0, NR_CPUS * sizeof(struct acpi_processor_performance)); - - /* register struct acpi_processor_performance performance */ - for (i=0; iflags.performance) - goto found_capable_cpu; - } - result = -ENODEV; - goto err0; - - found_capable_cpu: - result = cpufreq_register_driver(&acpi_cpufreq_driver); - if (result) - goto err0; - perf = pr->performance; - current_state = perf->state; - - if (current_state == pr->limit.state.px) { - result = acpi_processor_set_performance(perf, (perf->state_count - 1)); - if (result) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Disabled P-States due to failure while switching.\n")); - result = -ENODEV; - goto err1; - } - } - - result = acpi_processor_set_performance(perf, pr->limit.state.px); - if (result) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Disabled P-States due to failure while switching.\n")); - result = -ENODEV; - goto err1; - } - - if (current_state != 0) { - result = acpi_processor_set_performance(perf, current_state); - if (result) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Disabled P-States due to failure while switching.\n")); - result = -ENODEV; - goto err1; - } - } - - return_VALUE(0); - - /* error handling */ - err1: - cpufreq_unregister_driver(&acpi_cpufreq_driver); - - err0: - /* unregister struct acpi_processor_performance performance */ - for (i=0; iflags.performance = 0; - performance[i].pr->performance = NULL; - performance[i].pr = NULL; - } - } - kfree(performance); - - printk(KERN_INFO "cpufreq: No CPUs supporting ACPI performance management found.\n"); return_VALUE(result); } @@ -796,27 +380,9 @@ static void __exit acpi_cpufreq_exit (void) { - int i = 0; - ACPI_FUNCTION_TRACE("acpi_cpufreq_exit"); - for (i=0; iflags.performance = 0; - } - - cpufreq_unregister_driver(&acpi_cpufreq_driver); - - /* unregister struct acpi_processor_performance performance */ - for (i=0; iflags.performance = 0; - performance[i].pr->performance = NULL; - performance[i].pr = NULL; - } - } - - kfree(performance); + cpufreq_unregister_driver(&acpi_cpufreq_driver); return_VOID; } --- diff/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c 2004-02-09 10:39:50.000000000 +0000 @@ -57,8 +57,7 @@ u32 l, h; cpumask_t cpus_allowed, affected_cpu_map; struct cpufreq_freqs freqs; - int hyperthreading = 0; - int sibling = 0; + int j; if (!cpu_online(cpu) || (newstate > DC_DISABLE) || (newstate == DC_RESV)) @@ -68,13 +67,10 @@ cpus_allowed = current->cpus_allowed; /* only run on CPU to be set, or on its sibling */ - affected_cpu_map = cpumask_of_cpu(cpu); -#ifdef CONFIG_X86_HT - hyperthreading = ((cpu_has_ht) && (smp_num_siblings == 2)); - if (hyperthreading) { - sibling = cpu_sibling_map[cpu]; - cpu_set(sibling, affected_cpu_map); - } +#ifdef CONFIG_SMP + affected_cpu_map = cpu_sibling_map[cpu]; +#else + affected_cpu_map = cpumask_of_cpu(cpu); #endif set_cpus_allowed(current, affected_cpu_map); BUG_ON(!cpu_isset(smp_processor_id(), affected_cpu_map)); @@ -97,11 +93,11 @@ /* notifiers */ freqs.old = stock_freq * l / 8; freqs.new = stock_freq * newstate / 8; - freqs.cpu = cpu; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - if (hyperthreading) { - freqs.cpu = sibling; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + for_each_cpu(j) { + if (cpu_isset(j, affected_cpu_map)) { + freqs.cpu = j; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } } rdmsr(MSR_IA32_THERM_STATUS, l, h); @@ -132,10 +128,11 @@ set_cpus_allowed(current, cpus_allowed); /* notifiers */ - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - if (hyperthreading) { - freqs.cpu = cpu; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + for_each_cpu(j) { + if (cpu_isset(j, affected_cpu_map)) { + freqs.cpu = j; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } } return 0; --- diff/arch/i386/kernel/cpu/intel.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/i386/kernel/cpu/intel.c 2004-02-09 10:39:50.000000000 +0000 @@ -10,6 +10,7 @@ #include #include #include +#include #include "cpu.h" @@ -19,8 +20,6 @@ #include #endif -extern int trap_init_f00f_bug(void); - #ifdef CONFIG_X86_INTEL_USERCOPY /* * Alignment at which movsl is preferred for bulk memory copies. @@ -165,7 +164,7 @@ c->f00f_bug = 1; if ( !f00f_workaround_enabled ) { - trap_init_f00f_bug(); + trap_init_virtual_IDT(); printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n"); f00f_workaround_enabled = 1; } @@ -248,6 +247,12 @@ /* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until model 3 mask 3 */ if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633) clear_bit(X86_FEATURE_SEP, c->x86_capability); + /* + * FIXME: SEP is disabled for 4G/4G for now: + */ +#ifdef CONFIG_X86_HIGH_ENTRY + clear_bit(X86_FEATURE_SEP, c->x86_capability); +#endif /* Names for the Pentium II/Celeron processors detectable only by also checking the cache size. --- diff/arch/i386/kernel/cpu/proc.c 2003-08-26 10:00:51.000000000 +0100 +++ source/arch/i386/kernel/cpu/proc.c 2004-02-09 10:39:50.000000000 +0000 @@ -50,7 +50,7 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* VIA/Cyrix/Centaur-defined */ - NULL, NULL, "xstore", NULL, NULL, NULL, NULL, NULL, + NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, --- diff/arch/i386/kernel/cpuid.c 2003-09-17 12:28:01.000000000 +0100 +++ source/arch/i386/kernel/cpuid.c 2004-02-09 10:39:50.000000000 +0000 @@ -1,4 +1,3 @@ -#ident "$Id$" /* ----------------------------------------------------------------------- * * * Copyright 2000 H. Peter Anvin - All Rights Reserved --- diff/arch/i386/kernel/doublefault.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/kernel/doublefault.c 2004-02-09 10:39:50.000000000 +0000 @@ -7,12 +7,13 @@ #include #include #include +#include #define DOUBLEFAULT_STACKSIZE (1024) static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE]; #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE) -#define ptr_ok(x) ((x) > 0xc0000000 && (x) < 0xc1000000) +#define ptr_ok(x) (((x) > __PAGE_OFFSET && (x) < (__PAGE_OFFSET + 0x01000000)) || ((x) >= FIXADDR_START)) static void doublefault_fn(void) { @@ -38,8 +39,8 @@ printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n", t->eax, t->ebx, t->ecx, t->edx); - printk("esi = %08lx, edi = %08lx\n", - t->esi, t->edi); + printk("esi = %08lx, edi = %08lx, ebp = %08lx\n", + t->esi, t->edi, t->ebp); } } --- diff/arch/i386/kernel/edd.c 2003-10-27 09:20:36.000000000 +0000 +++ source/arch/i386/kernel/edd.c 2004-02-09 10:39:50.000000000 +0000 @@ -2,6 +2,7 @@ * linux/arch/i386/kernel/edd.c * Copyright (C) 2002, 2003 Dell Inc. * by Matt Domsch + * disk80 signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya * * BIOS Enhanced Disk Drive Services (EDD) * conformant to T13 Committee www.t13.org @@ -59,9 +60,9 @@ MODULE_DESCRIPTION("sysfs interface to BIOS EDD information"); MODULE_LICENSE("GPL"); -#define EDD_VERSION "0.10 2003-Oct-11" +#define EDD_VERSION "0.12 2004-Jan-26" #define EDD_DEVICE_NAME_SIZE 16 -#define REPORT_URL "http://domsch.com/linux/edd30/results.html" +#define REPORT_URL "http://linux.dell.com/edd/results.html" #define left (PAGE_SIZE - (p - buf) - 1) @@ -133,18 +134,18 @@ for (i = 0; i < 4; i++) { if (isprint(info->params.host_bus_type[i])) { - p += snprintf(p, left, "%c", info->params.host_bus_type[i]); + p += scnprintf(p, left, "%c", info->params.host_bus_type[i]); } else { - p += snprintf(p, left, " "); + p += scnprintf(p, left, " "); } } if (!strncmp(info->params.host_bus_type, "ISA", 3)) { - p += snprintf(p, left, "\tbase_address: %x\n", + p += scnprintf(p, left, "\tbase_address: %x\n", info->params.interface_path.isa.base_address); } else if (!strncmp(info->params.host_bus_type, "PCIX", 4) || !strncmp(info->params.host_bus_type, "PCI", 3)) { - p += snprintf(p, left, + p += scnprintf(p, left, "\t%02x:%02x.%d channel: %u\n", info->params.interface_path.pci.bus, info->params.interface_path.pci.slot, @@ -153,12 +154,12 @@ } else if (!strncmp(info->params.host_bus_type, "IBND", 4) || !strncmp(info->params.host_bus_type, "XPRS", 4) || !strncmp(info->params.host_bus_type, "HTPT", 4)) { - p += snprintf(p, left, + p += scnprintf(p, left, "\tTBD: %llx\n", info->params.interface_path.ibnd.reserved); } else { - p += snprintf(p, left, "\tunknown: %llx\n", + p += scnprintf(p, left, "\tunknown: %llx\n", info->params.interface_path.unknown.reserved); } return (p - buf); @@ -177,43 +178,43 @@ for (i = 0; i < 8; i++) { if (isprint(info->params.interface_type[i])) { - p += snprintf(p, left, "%c", info->params.interface_type[i]); + p += scnprintf(p, left, "%c", info->params.interface_type[i]); } else { - p += snprintf(p, left, " "); + p += scnprintf(p, left, " "); } } if (!strncmp(info->params.interface_type, "ATAPI", 5)) { - p += snprintf(p, left, "\tdevice: %u lun: %u\n", + p += scnprintf(p, left, "\tdevice: %u lun: %u\n", info->params.device_path.atapi.device, info->params.device_path.atapi.lun); } else if (!strncmp(info->params.interface_type, "ATA", 3)) { - p += snprintf(p, left, "\tdevice: %u\n", + p += scnprintf(p, left, "\tdevice: %u\n", info->params.device_path.ata.device); } else if (!strncmp(info->params.interface_type, "SCSI", 4)) { - p += snprintf(p, left, "\tid: %u lun: %llu\n", + p += scnprintf(p, left, "\tid: %u lun: %llu\n", info->params.device_path.scsi.id, info->params.device_path.scsi.lun); } else if (!strncmp(info->params.interface_type, "USB", 3)) { - p += snprintf(p, left, "\tserial_number: %llx\n", + p += scnprintf(p, left, "\tserial_number: %llx\n", info->params.device_path.usb.serial_number); } else if (!strncmp(info->params.interface_type, "1394", 4)) { - p += snprintf(p, left, "\teui: %llx\n", + p += scnprintf(p, left, "\teui: %llx\n", info->params.device_path.i1394.eui); } else if (!strncmp(info->params.interface_type, "FIBRE", 5)) { - p += snprintf(p, left, "\twwid: %llx lun: %llx\n", + p += scnprintf(p, left, "\twwid: %llx lun: %llx\n", info->params.device_path.fibre.wwid, info->params.device_path.fibre.lun); } else if (!strncmp(info->params.interface_type, "I2O", 3)) { - p += snprintf(p, left, "\tidentity_tag: %llx\n", + p += scnprintf(p, left, "\tidentity_tag: %llx\n", info->params.device_path.i2o.identity_tag); } else if (!strncmp(info->params.interface_type, "RAID", 4)) { - p += snprintf(p, left, "\tidentity_tag: %x\n", + p += scnprintf(p, left, "\tidentity_tag: %x\n", info->params.device_path.raid.array_number); } else if (!strncmp(info->params.interface_type, "SATA", 4)) { - p += snprintf(p, left, "\tdevice: %u\n", + p += scnprintf(p, left, "\tdevice: %u\n", info->params.device_path.sata.device); } else { - p += snprintf(p, left, "\tunknown: %llx %llx\n", + p += scnprintf(p, left, "\tunknown: %llx %llx\n", info->params.device_path.unknown.reserved1, info->params.device_path.unknown.reserved2); } @@ -255,7 +256,15 @@ return -EINVAL; } - p += snprintf(p, left, "0x%02x\n", info->version); + p += scnprintf(p, left, "0x%02x\n", info->version); + return (p - buf); +} + +static ssize_t +edd_show_disk80_sig(struct edd_device *edev, char *buf) +{ + char *p = buf; + p += scnprintf(p, left, "0x%08x\n", edd_disk80_sig); return (p - buf); } @@ -269,16 +278,16 @@ } if (info->interface_support & EDD_EXT_FIXED_DISK_ACCESS) { - p += snprintf(p, left, "Fixed disk access\n"); + p += scnprintf(p, left, "Fixed disk access\n"); } if (info->interface_support & EDD_EXT_DEVICE_LOCKING_AND_EJECTING) { - p += snprintf(p, left, "Device locking and ejecting\n"); + p += scnprintf(p, left, "Device locking and ejecting\n"); } if (info->interface_support & EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT) { - p += snprintf(p, left, "Enhanced Disk Drive support\n"); + p += scnprintf(p, left, "Enhanced Disk Drive support\n"); } if (info->interface_support & EDD_EXT_64BIT_EXTENSIONS) { - p += snprintf(p, left, "64-bit extensions\n"); + p += scnprintf(p, left, "64-bit extensions\n"); } return (p - buf); } @@ -293,21 +302,21 @@ } if (info->params.info_flags & EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT) - p += snprintf(p, left, "DMA boundary error transparent\n"); + p += scnprintf(p, left, "DMA boundary error transparent\n"); if (info->params.info_flags & EDD_INFO_GEOMETRY_VALID) - p += snprintf(p, left, "geometry valid\n"); + p += scnprintf(p, left, "geometry valid\n"); if (info->params.info_flags & EDD_INFO_REMOVABLE) - p += snprintf(p, left, "removable\n"); + p += scnprintf(p, left, "removable\n"); if (info->params.info_flags & EDD_INFO_WRITE_VERIFY) - p += snprintf(p, left, "write verify\n"); + p += scnprintf(p, left, "write verify\n"); if (info->params.info_flags & EDD_INFO_MEDIA_CHANGE_NOTIFICATION) - p += snprintf(p, left, "media change notification\n"); + p += scnprintf(p, left, "media change notification\n"); if (info->params.info_flags & EDD_INFO_LOCKABLE) - p += snprintf(p, left, "lockable\n"); + p += scnprintf(p, left, "lockable\n"); if (info->params.info_flags & EDD_INFO_NO_MEDIA_PRESENT) - p += snprintf(p, left, "no media present\n"); + p += scnprintf(p, left, "no media present\n"); if (info->params.info_flags & EDD_INFO_USE_INT13_FN50) - p += snprintf(p, left, "use int13 fn50\n"); + p += scnprintf(p, left, "use int13 fn50\n"); return (p - buf); } @@ -320,7 +329,7 @@ return -EINVAL; } - p += snprintf(p, left, "0x%x\n", info->params.num_default_cylinders); + p += scnprintf(p, left, "0x%x\n", info->params.num_default_cylinders); return (p - buf); } @@ -333,7 +342,7 @@ return -EINVAL; } - p += snprintf(p, left, "0x%x\n", info->params.num_default_heads); + p += scnprintf(p, left, "0x%x\n", info->params.num_default_heads); return (p - buf); } @@ -346,7 +355,7 @@ return -EINVAL; } - p += snprintf(p, left, "0x%x\n", info->params.sectors_per_track); + p += scnprintf(p, left, "0x%x\n", info->params.sectors_per_track); return (p - buf); } @@ -359,7 +368,7 @@ return -EINVAL; } - p += snprintf(p, left, "0x%llx\n", info->params.number_of_sectors); + p += scnprintf(p, left, "0x%llx\n", info->params.number_of_sectors); return (p - buf); } @@ -429,6 +438,15 @@ return 1; } +static int +edd_has_disk80_sig(struct edd_device *edev) +{ + struct edd_info *info = edd_dev_get_info(edev); + if (!edev || !info) + return 0; + return info->device == 0x80; +} + static EDD_DEVICE_ATTR(raw_data, 0444, edd_show_raw_data, NULL); static EDD_DEVICE_ATTR(version, 0444, edd_show_version, NULL); static EDD_DEVICE_ATTR(extensions, 0444, edd_show_extensions, NULL); @@ -443,6 +461,7 @@ edd_has_default_sectors_per_track); static EDD_DEVICE_ATTR(interface, 0444, edd_show_interface, edd_has_edd30); static EDD_DEVICE_ATTR(host_bus, 0444, edd_show_host_bus, edd_has_edd30); +static EDD_DEVICE_ATTR(mbr_signature, 0444, edd_show_disk80_sig, edd_has_disk80_sig); /* These are default attributes that are added for every edd @@ -464,6 +483,7 @@ &edd_attr_default_sectors_per_track, &edd_attr_interface, &edd_attr_host_bus, + &edd_attr_mbr_signature, NULL, }; --- diff/arch/i386/kernel/entry.S 2003-11-25 15:24:57.000000000 +0000 +++ source/arch/i386/kernel/entry.S 2004-02-09 10:39:50.000000000 +0000 @@ -43,11 +43,25 @@ #include #include #include +#include #include #include +#include #include #include #include "irq_vectors.h" + /* We do not recover from a stack overflow, but at least + * we know it happened and should be able to track it down. + */ +#ifdef CONFIG_STACK_OVERFLOW_TEST +#define STACK_OVERFLOW_TEST \ + testl $7680,%esp; \ + jnz 10f; \ + call stack_overflow; \ +10: +#else +#define STACK_OVERFLOW_TEST +#endif #define nr_syscalls ((syscall_table_size)/4) @@ -87,7 +101,102 @@ #define resume_kernel restore_all #endif -#define SAVE_ALL \ +#ifdef CONFIG_X86_HIGH_ENTRY + +#ifdef CONFIG_X86_SWITCH_PAGETABLES + +#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) +/* + * If task is preempted in __SWITCH_KERNELSPACE, and moved to another cpu, + * __switch_to repoints %esp to the appropriate virtual stack; but %ebp is + * left stale, so we must check whether to repeat the real stack calculation. + */ +#define repeat_if_esp_changed \ + xorl %esp, %ebp; \ + testl $0xffffe000, %ebp; \ + jnz 0b +#else +#define repeat_if_esp_changed +#endif + +/* clobbers ebx, edx and ebp */ + +#define __SWITCH_KERNELSPACE \ + cmpl $0xff000000, %esp; \ + jb 1f; \ + \ + /* \ + * switch pagetables and load the real stack, \ + * keep the stack offset: \ + */ \ + \ + movl $swapper_pg_dir-__PAGE_OFFSET, %edx; \ + \ + /* GET_THREAD_INFO(%ebp) intermixed */ \ +0: \ + movl %esp, %ebp; \ + movl %esp, %ebx; \ + andl $0xffffe000, %ebp; \ + andl $0x00001fff, %ebx; \ + orl TI_real_stack(%ebp), %ebx; \ + repeat_if_esp_changed; \ + \ + movl %edx, %cr3; \ + movl %ebx, %esp; \ +1: + +#endif + + +#define __SWITCH_USERSPACE \ + /* interrupted any of the user return paths? */ \ + \ + movl EIP(%esp), %eax; \ + \ + cmpl $int80_ret_start_marker, %eax; \ + jb 33f; /* nope - continue with sysexit check */\ + cmpl $int80_ret_end_marker, %eax; \ + jb 22f; /* yes - switch to virtual stack */ \ +33: \ + cmpl $sysexit_ret_start_marker, %eax; \ + jb 44f; /* nope - continue with user check */ \ + cmpl $sysexit_ret_end_marker, %eax; \ + jb 22f; /* yes - switch to virtual stack */ \ + /* return to userspace? */ \ +44: \ + movl EFLAGS(%esp),%ecx; \ + movb CS(%esp),%cl; \ + testl $(VM_MASK | 3),%ecx; \ + jz 2f; \ +22: \ + /* \ + * switch to the virtual stack, then switch to \ + * the userspace pagetables. \ + */ \ + \ + GET_THREAD_INFO(%ebp); \ + movl TI_virtual_stack(%ebp), %edx; \ + movl TI_user_pgd(%ebp), %ecx; \ + \ + movl %esp, %ebx; \ + andl $0x1fff, %ebx; \ + orl %ebx, %edx; \ +int80_ret_start_marker: \ + movl %edx, %esp; \ + movl %ecx, %cr3; \ + \ + __RESTORE_ALL; \ +int80_ret_end_marker: \ +2: + +#else /* !CONFIG_X86_HIGH_ENTRY */ + +#define __SWITCH_KERNELSPACE +#define __SWITCH_USERSPACE + +#endif + +#define __SAVE_ALL \ cld; \ pushl %es; \ pushl %ds; \ @@ -102,7 +211,7 @@ movl %edx, %ds; \ movl %edx, %es; -#define RESTORE_INT_REGS \ +#define __RESTORE_INT_REGS \ popl %ebx; \ popl %ecx; \ popl %edx; \ @@ -111,29 +220,28 @@ popl %ebp; \ popl %eax -#define RESTORE_REGS \ - RESTORE_INT_REGS; \ -1: popl %ds; \ -2: popl %es; \ +#define __RESTORE_REGS \ + __RESTORE_INT_REGS; \ +111: popl %ds; \ +222: popl %es; \ .section .fixup,"ax"; \ -3: movl $0,(%esp); \ - jmp 1b; \ -4: movl $0,(%esp); \ - jmp 2b; \ +444: movl $0,(%esp); \ + jmp 111b; \ +555: movl $0,(%esp); \ + jmp 222b; \ .previous; \ .section __ex_table,"a";\ .align 4; \ - .long 1b,3b; \ - .long 2b,4b; \ + .long 111b,444b;\ + .long 222b,555b;\ .previous - -#define RESTORE_ALL \ - RESTORE_REGS \ +#define __RESTORE_ALL \ + __RESTORE_REGS \ addl $4, %esp; \ -1: iret; \ +333: iret; \ .section .fixup,"ax"; \ -2: sti; \ +666: sti; \ movl $(__USER_DS), %edx; \ movl %edx, %ds; \ movl %edx, %es; \ @@ -142,10 +250,19 @@ .previous; \ .section __ex_table,"a";\ .align 4; \ - .long 1b,2b; \ + .long 333b,666b;\ .previous +#define SAVE_ALL \ + __SAVE_ALL; \ + __SWITCH_KERNELSPACE; \ + STACK_OVERFLOW_TEST; + +#define RESTORE_ALL \ + __SWITCH_USERSPACE; \ + __RESTORE_ALL; +.section .entry.text,"ax" ENTRY(lcall7) pushfl # We get a different stack layout with call @@ -163,7 +280,7 @@ movl %edx,EIP(%ebp) # Now we move them to their "normal" places movl %ecx,CS(%ebp) # andl $-8192, %ebp # GET_THREAD_INFO - movl TI_EXEC_DOMAIN(%ebp), %edx # Get the execution domain + movl TI_exec_domain(%ebp), %edx # Get the execution domain call *4(%edx) # Call the lcall7 handler for the domain addl $4, %esp popl %eax @@ -208,7 +325,7 @@ cli # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx andl $_TIF_WORK_MASK, %ecx # is there any work to be done on # int/exception return? jne work_pending @@ -216,18 +333,18 @@ #ifdef CONFIG_PREEMPT ENTRY(resume_kernel) - cmpl $0,TI_PRE_COUNT(%ebp) # non-zero preempt_count ? + cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? jnz restore_all need_resched: - movl TI_FLAGS(%ebp), %ecx # need_resched set ? + movl TI_flags(%ebp), %ecx # need_resched set ? testb $_TIF_NEED_RESCHED, %cl jz restore_all testl $IF_MASK,EFLAGS(%esp) # interrupts off (exception path) ? jz restore_all - movl $PREEMPT_ACTIVE,TI_PRE_COUNT(%ebp) + movl $PREEMPT_ACTIVE,TI_preempt_count(%ebp) sti call schedule - movl $0,TI_PRE_COUNT(%ebp) + movl $0,TI_preempt_count(%ebp) cli jmp need_resched #endif @@ -246,37 +363,50 @@ pushl $(__USER_CS) pushl $SYSENTER_RETURN -/* - * Load the potential sixth argument from user stack. - * Careful about security. - */ - cmpl $__PAGE_OFFSET-3,%ebp - jae syscall_fault -1: movl (%ebp),%ebp -.section __ex_table,"a" - .align 4 - .long 1b,syscall_fault -.previous - pushl %eax SAVE_ALL GET_THREAD_INFO(%ebp) cmpl $(nr_syscalls), %eax jae syscall_badsys - testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp) + testb $_TIF_SYSCALL_TRACE,TI_flags(%ebp) jnz syscall_trace_entry call *sys_call_table(,%eax,4) movl %eax,EAX(%esp) cli - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx testw $_TIF_ALLWORK_MASK, %cx jne syscall_exit_work + +#ifdef CONFIG_X86_SWITCH_PAGETABLES + + GET_THREAD_INFO(%ebp) + movl TI_virtual_stack(%ebp), %edx + movl TI_user_pgd(%ebp), %ecx + movl %esp, %ebx + andl $0x1fff, %ebx + orl %ebx, %edx +sysexit_ret_start_marker: + movl %edx, %esp + movl %ecx, %cr3 +#endif + /* + * only ebx is not restored by the userspace sysenter vsyscall + * code, it assumes it to be callee-saved. + */ + movl EBX(%esp), %ebx + /* if something modifies registers it must also disable sysexit */ + movl EIP(%esp), %edx movl OLDESP(%esp), %ecx + sti sysexit +#ifdef CONFIG_X86_SWITCH_PAGETABLES +sysexit_ret_end_marker: + nop +#endif # system call handler stub @@ -287,7 +417,7 @@ cmpl $(nr_syscalls), %eax jae syscall_badsys # system call tracing in operation - testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp) + testb $_TIF_SYSCALL_TRACE,TI_flags(%ebp) jnz syscall_trace_entry syscall_call: call *sys_call_table(,%eax,4) @@ -296,10 +426,23 @@ cli # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx testw $_TIF_ALLWORK_MASK, %cx # current->work jne syscall_exit_work restore_all: +#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS + movl EFLAGS(%esp), %eax # mix EFLAGS and CS + movb CS(%esp), %al + testl $(VM_MASK | 3), %eax + jz resume_kernelX # returning to kernel or vm86-space + + cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? + jz resume_kernelX + + int $3 + +resume_kernelX: +#endif RESTORE_ALL # perform work that needs to be done immediately before resumption @@ -312,7 +455,7 @@ cli # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret - movl TI_FLAGS(%ebp), %ecx + movl TI_flags(%ebp), %ecx andl $_TIF_WORK_MASK, %ecx # is there any work to be done other # than syscall tracing? jz restore_all @@ -327,6 +470,22 @@ # vm86-space xorl %edx, %edx call do_notify_resume + +#if CONFIG_X86_HIGH_ENTRY + /* + * Reload db7 if necessary: + */ + movl TI_flags(%ebp), %ecx + testb $_TIF_DB7, %cl + jnz work_db7 + + jmp restore_all + +work_db7: + movl TI_task(%ebp), %edx; + movl task_thread_db7(%edx), %edx; + movl %edx, %db7; +#endif jmp restore_all ALIGN @@ -382,7 +541,7 @@ */ .data ENTRY(interrupt) -.text +.previous vector=0 ENTRY(irq_entries_start) @@ -392,7 +551,7 @@ jmp common_interrupt .data .long 1b -.text +.previous vector=vector+1 .endr @@ -433,12 +592,17 @@ movl ES(%esp), %edi # get the function address movl %eax, ORIG_EAX(%esp) movl %ecx, ES(%esp) - movl %esp, %edx pushl %esi # push the error code - pushl %edx # push the pt_regs pointer movl $(__USER_DS), %edx movl %edx, %ds movl %edx, %es + +/* clobbers edx, ebx and ebp */ + __SWITCH_KERNELSPACE + + leal 4(%esp), %edx # prepare pt_regs + pushl %edx # push pt_regs + call *%edi addl $8, %esp jmp ret_from_exception @@ -529,7 +693,7 @@ pushl %edx call do_nmi addl $8, %esp - RESTORE_ALL + jmp restore_all nmi_stack_fixup: FIX_STACK(12,nmi_stack_correct, 1) @@ -606,6 +770,8 @@ pushl $do_spurious_interrupt_bug jmp error_code +.previous + .data ENTRY(sys_call_table) .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ @@ -882,5 +1048,8 @@ .long sys_utimes .long sys_fadvise64_64 .long sys_ni_syscall /* sys_vserver */ + .long sys_ni_syscall /* mbind */ + .long sys_ni_syscall /* get_mempolicy */ + .long sys_ni_syscall /* set_mempolicy */ syscall_table_size=(.-sys_call_table) --- diff/arch/i386/kernel/head.S 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/kernel/head.S 2004-02-09 10:39:50.000000000 +0000 @@ -16,6 +16,7 @@ #include #include #include +#include #define OLD_CL_MAGIC_ADDR 0x90020 #define OLD_CL_MAGIC 0xA33F @@ -330,7 +331,7 @@ /* This is the default interrupt "handler" :-) */ int_msg: - .asciz "Unknown interrupt\n" + .asciz "Unknown interrupt or fault at EIP %p %p %p\n" ALIGN ignore_int: cld @@ -342,9 +343,17 @@ movl $(__KERNEL_DS),%eax movl %eax,%ds movl %eax,%es + pushl 16(%esp) + pushl 24(%esp) + pushl 32(%esp) + pushl 40(%esp) pushl $int_msg call printk popl %eax + popl %eax + popl %eax + popl %eax + popl %eax popl %ds popl %es popl %edx @@ -377,23 +386,27 @@ .fill NR_CPUS-1,8,0 # space for the other GDT descriptors /* - * This is initialized to create an identity-mapping at 0-8M (for bootup - * purposes) and another mapping of the 0-8M area at virtual address + * This is initialized to create an identity-mapping at 0-16M (for bootup + * purposes) and another mapping of the 0-16M area at virtual address * PAGE_OFFSET. */ .org 0x1000 ENTRY(swapper_pg_dir) .long 0x00102007 .long 0x00103007 - .fill BOOT_USER_PGD_PTRS-2,4,0 - /* default: 766 entries */ + .long 0x00104007 + .long 0x00105007 + .fill BOOT_USER_PGD_PTRS-4,4,0 + /* default: 764 entries */ .long 0x00102007 .long 0x00103007 - /* default: 254 entries */ - .fill BOOT_KERNEL_PGD_PTRS-2,4,0 + .long 0x00104007 + .long 0x00105007 + /* default: 252 entries */ + .fill BOOT_KERNEL_PGD_PTRS-4,4,0 /* - * The page tables are initialized to only 8MB here - the final page + * The page tables are initialized to only 16MB here - the final page * tables are set up later depending on memory size. */ .org 0x2000 @@ -402,15 +415,21 @@ .org 0x3000 ENTRY(pg1) +.org 0x4000 +ENTRY(pg2) + +.org 0x5000 +ENTRY(pg3) + /* * empty_zero_page must immediately follow the page tables ! (The * initialization loop counts until empty_zero_page) */ -.org 0x4000 +.org 0x6000 ENTRY(empty_zero_page) -.org 0x5000 +.org 0x7000 /* * Real beginning of normal "text" segment @@ -419,12 +438,12 @@ ENTRY(_stext) /* - * This starts the data section. Note that the above is all - * in the text section because it has alignment requirements - * that we cannot fulfill any other way. + * This starts the data section. */ .data +.align PAGE_SIZE_asm + /* * The Global Descriptor Table contains 28 quadwords, per-CPU. */ @@ -439,7 +458,9 @@ .quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */ .quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */ #endif - .align L1_CACHE_BYTES + +.align PAGE_SIZE_asm + ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* NULL descriptor */ .quad 0x0000000000000000 /* 0x0b reserved */ --- diff/arch/i386/kernel/i386_ksyms.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/i386/kernel/i386_ksyms.c 2004-02-09 10:39:50.000000000 +0000 @@ -32,7 +32,6 @@ #include #include #include -#include #include extern void dump_thread(struct pt_regs *, struct user *); @@ -98,7 +97,6 @@ EXPORT_SYMBOL_NOVERS(__down_failed_trylock); EXPORT_SYMBOL_NOVERS(__up_wakeup); /* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial_copy_generic); /* Delay loops */ EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(__udelay); @@ -112,13 +110,17 @@ EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); +#if !defined(CONFIG_X86_UACCESS_INDIRECT) EXPORT_SYMBOL(strncpy_from_user); -EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(__direct_strncpy_from_user); EXPORT_SYMBOL(clear_user); EXPORT_SYMBOL(__clear_user); EXPORT_SYMBOL(__copy_from_user_ll); EXPORT_SYMBOL(__copy_to_user_ll); EXPORT_SYMBOL(strnlen_user); +#else /* CONFIG_X86_UACCESS_INDIRECT */ +EXPORT_SYMBOL(direct_csum_partial_copy_generic); +#endif EXPORT_SYMBOL(dma_alloc_coherent); EXPORT_SYMBOL(dma_free_coherent); @@ -203,11 +205,6 @@ EXPORT_SYMBOL(kmap_atomic_to_page); #endif -#ifdef CONFIG_EDD_MODULE -EXPORT_SYMBOL(edd); -EXPORT_SYMBOL(eddnr); -#endif - #if defined(CONFIG_X86_SPEEDSTEP_SMI) || defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE) EXPORT_SYMBOL(ist_info); #endif --- diff/arch/i386/kernel/i387.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/i386/kernel/i387.c 2004-02-09 10:39:50.000000000 +0000 @@ -218,6 +218,7 @@ static int convert_fxsr_to_user( struct _fpstate __user *buf, struct i387_fxsave_struct *fxsave ) { + struct _fpreg tmp[8]; /* 80 bytes scratch area */ unsigned long env[7]; struct _fpreg __user *to; struct _fpxreg *from; @@ -234,23 +235,25 @@ if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) ) return 1; - to = &buf->_st[0]; + to = tmp; from = (struct _fpxreg *) &fxsave->st_space[0]; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { unsigned long *t = (unsigned long *)to; unsigned long *f = (unsigned long *)from; - if (__put_user(*f, t) || - __put_user(*(f + 1), t + 1) || - __put_user(from->exponent, &to->exponent)) - return 1; + *t = *f; + *(t + 1) = *(f+1); + to->exponent = from->exponent; } + if (copy_to_user(buf->_st, tmp, sizeof(struct _fpreg [8]))) + return 1; return 0; } static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave, struct _fpstate __user *buf ) { + struct _fpreg tmp[8]; /* 80 bytes scratch area */ unsigned long env[7]; struct _fpxreg *to; struct _fpreg __user *from; @@ -258,6 +261,8 @@ if ( __copy_from_user( env, buf, 7 * sizeof(long) ) ) return 1; + if (copy_from_user(tmp, buf->_st, sizeof(struct _fpreg [8]))) + return 1; fxsave->cwd = (unsigned short)(env[0] & 0xffff); fxsave->swd = (unsigned short)(env[1] & 0xffff); @@ -269,15 +274,14 @@ fxsave->fos = env[6]; to = (struct _fpxreg *) &fxsave->st_space[0]; - from = &buf->_st[0]; + from = tmp; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { unsigned long *t = (unsigned long *)to; unsigned long *f = (unsigned long *)from; - if (__get_user(*t, f) || - __get_user(*(t + 1), f + 1) || - __get_user(to->exponent, &from->exponent)) - return 1; + *t = *f; + *(t + 1) = *(f + 1); + to->exponent = from->exponent; } return 0; } @@ -451,15 +455,18 @@ int set_fpxregs( struct task_struct *tsk, struct user_fxsr_struct __user *buf ) { + int ret = 0; + if ( cpu_has_fxsr ) { - __copy_from_user( &tsk->thread.i387.fxsave, buf, - sizeof(struct user_fxsr_struct) ); + if (__copy_from_user( &tsk->thread.i387.fxsave, buf, + sizeof(struct user_fxsr_struct) )) + ret = -EFAULT; /* mxcsr bit 6 and 31-16 must be zero for security reasons */ tsk->thread.i387.fxsave.mxcsr &= 0xffbf; - return 0; } else { - return -EIO; + ret = -EIO; } + return ret; } /* --- diff/arch/i386/kernel/init_task.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/i386/kernel/init_task.c 2004-02-09 10:39:50.000000000 +0000 @@ -26,7 +26,7 @@ */ union thread_union init_thread_union __attribute__((__section__(".data.init_task"))) = - { INIT_THREAD_INFO(init_task) }; + { INIT_THREAD_INFO(init_task, init_thread_union) }; /* * Initial task structure. @@ -44,5 +44,5 @@ * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ -struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS }; +struct tss_struct init_tss[NR_CPUS] __attribute__((__section__(".data.tss"))) = { [0 ... NR_CPUS-1] = INIT_TSS }; --- diff/arch/i386/kernel/io_apic.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/i386/kernel/io_apic.c 2004-02-09 10:39:50.000000000 +0000 @@ -317,8 +317,7 @@ #define IRQ_ALLOWED(cpu, allowed_mask) cpu_isset(cpu, allowed_mask) -#define CPU_TO_PACKAGEINDEX(i) \ - ((physical_balance && i > cpu_sibling_map[i]) ? cpu_sibling_map[i] : i) +#define CPU_TO_PACKAGEINDEX(i) (first_cpu(cpu_sibling_map[i])) #define MAX_BALANCED_IRQ_INTERVAL (5*HZ) #define MIN_BALANCED_IRQ_INTERVAL (HZ/2) @@ -401,6 +400,7 @@ unsigned long max_cpu_irq = 0, min_cpu_irq = (~0); unsigned long move_this_load = 0; int max_loaded = 0, min_loaded = 0; + int load; unsigned long useful_load_threshold = balanced_irq_interval + 10; int selected_irq; int tmp_loaded, first_attempt = 1; @@ -452,7 +452,7 @@ for (i = 0; i < NR_CPUS; i++) { if (!cpu_online(i)) continue; - if (physical_balance && i > cpu_sibling_map[i]) + if (i != CPU_TO_PACKAGEINDEX(i)) continue; if (min_cpu_irq > CPU_IRQ(i)) { min_cpu_irq = CPU_IRQ(i); @@ -471,7 +471,7 @@ for (i = 0; i < NR_CPUS; i++) { if (!cpu_online(i)) continue; - if (physical_balance && i > cpu_sibling_map[i]) + if (i != CPU_TO_PACKAGEINDEX(i)) continue; if (max_cpu_irq <= CPU_IRQ(i)) continue; @@ -551,9 +551,14 @@ * We seek the least loaded sibling by making the comparison * (A+B)/2 vs B */ - if (physical_balance && (CPU_IRQ(min_loaded) >> 1) > - CPU_IRQ(cpu_sibling_map[min_loaded])) - min_loaded = cpu_sibling_map[min_loaded]; + load = CPU_IRQ(min_loaded) >> 1; + for_each_cpu_mask(j, cpu_sibling_map[min_loaded]) { + if (load > CPU_IRQ(j)) { + /* This won't change cpu_sibling_map[min_loaded] */ + load = CPU_IRQ(j); + min_loaded = j; + } + } cpus_and(allowed_mask, cpu_online_map, irq_affinity[selected_irq]); target_cpu_mask = cpumask_of_cpu(min_loaded); --- diff/arch/i386/kernel/irq.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/i386/kernel/irq.c 2004-02-09 10:39:50.000000000 +0000 @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include @@ -508,6 +510,8 @@ irq_exit(); + kgdb_process_breakpoint(); + return 1; } @@ -962,7 +966,71 @@ return full_count; } +#endif + +#ifdef CONFIG_HOTPLUG_CPU +#include + +static void migrate_irqs_from(int cpu) +{ + cpumask_t mask; + unsigned int irq; + + mask = cpumask_of_cpu(cpu); + cpus_complement(mask); + cpus_and(mask, mask, cpu_online_map); + for (irq = 0; irq < NR_IRQS; irq++) { + cpus_and(irq_affinity[irq], irq_affinity[irq], mask); + if (cpus_empty(irq_affinity[irq])) + irq_affinity[irq] = cpumask_of_cpu(0); + if (irq_desc[irq].handler->set_affinity) + irq_desc[irq].handler->set_affinity(irq, mask); + } +} + +void enable_all_irqs(int cpu) +{ + cpumask_t mask; + unsigned int irq; + + mask = cpumask_of_cpu(cpu); + cpus_or(mask, mask, cpu_online_map); + for (irq = 0; irq < NR_IRQS; irq++) { + cpus_or(irq_affinity[irq], irq_affinity[irq], mask); + if (cpus_empty(irq_affinity[irq])) { + irq_affinity[irq] = cpumask_of_cpu(0); + } + + if (irq_desc[irq].handler->set_affinity) + irq_desc[irq].handler->set_affinity(irq, mask); + } +} + +static int irqs_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + int cpu = (int)hcpu; + switch(action) { + case CPU_ONLINE: + /* + * We could go through all the irqs and add + * this processor to the cpu set - zwane + */ + enable_all_irqs(cpu); + break; + case CPU_OFFLINE: + migrate_irqs_from(cpu); + break; + default: + break; + } + return NOTIFY_OK; +} + +static struct notifier_block __devinitdata irqs_cpu_nb = { + .notifier_call = irqs_cpu_notify, +}; #endif static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, @@ -1051,5 +1119,9 @@ */ for (i = 0; i < NR_IRQS; i++) register_irq_proc(i); +#ifdef CONFIG_HOTPLUG_CPU + register_cpu_notifier(&irqs_cpu_nb); +#endif + } --- diff/arch/i386/kernel/ldt.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/kernel/ldt.c 2004-02-09 10:39:50.000000000 +0000 @@ -2,7 +2,7 @@ * linux/kernel/ldt.c * * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds - * Copyright (C) 1999 Ingo Molnar + * Copyright (C) 1999, 2003 Ingo Molnar */ #include @@ -18,6 +18,8 @@ #include #include #include +#include +#include #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ static void flush_ldt(void *null) @@ -29,34 +31,31 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload) { - void *oldldt; - void *newldt; - int oldsize; + int oldsize, newsize, i; if (mincount <= pc->size) return 0; + /* + * LDT got larger - reallocate if necessary. + */ oldsize = pc->size; mincount = (mincount+511)&(~511); - if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE) - newldt = vmalloc(mincount*LDT_ENTRY_SIZE); - else - newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL); - - if (!newldt) - return -ENOMEM; - - if (oldsize) - memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE); - oldldt = pc->ldt; - memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE); - pc->ldt = newldt; - wmb(); + newsize = mincount*LDT_ENTRY_SIZE; + for (i = 0; i < newsize; i += PAGE_SIZE) { + int nr = i/PAGE_SIZE; + BUG_ON(i >= 64*1024); + if (!pc->ldt_pages[nr]) { + pc->ldt_pages[nr] = alloc_page(GFP_HIGHUSER); + if (!pc->ldt_pages[nr]) + return -ENOMEM; + clear_highpage(pc->ldt_pages[nr]); + } + } pc->size = mincount; - wmb(); - if (reload) { #ifdef CONFIG_SMP cpumask_t mask; + preempt_disable(); load_LDT(pc); mask = cpumask_of_cpu(smp_processor_id()); @@ -67,21 +66,20 @@ load_LDT(pc); #endif } - if (oldsize) { - if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE) - vfree(oldldt); - else - kfree(oldldt); - } return 0; } static inline int copy_ldt(mm_context_t *new, mm_context_t *old) { - int err = alloc_ldt(new, old->size, 0); - if (err < 0) + int i, err, size = old->size, nr_pages = (size*LDT_ENTRY_SIZE + PAGE_SIZE-1)/PAGE_SIZE; + + err = alloc_ldt(new, size, 0); + if (err < 0) { + new->size = 0; return err; - memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); + } + for (i = 0; i < nr_pages; i++) + copy_user_highpage(new->ldt_pages[i], old->ldt_pages[i], 0); return 0; } @@ -96,6 +94,7 @@ init_MUTEX(&mm->context.sem); mm->context.size = 0; + memset(mm->context.ldt_pages, 0, sizeof(struct page *) * MAX_LDT_PAGES); old_mm = current->mm; if (old_mm && old_mm->context.size > 0) { down(&old_mm->context.sem); @@ -107,23 +106,21 @@ /* * No need to lock the MM as we are the last user + * Do not touch the ldt register, we are already + * in the next thread. */ void destroy_context(struct mm_struct *mm) { - if (mm->context.size) { - if (mm == current->active_mm) - clear_LDT(); - if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE) - vfree(mm->context.ldt); - else - kfree(mm->context.ldt); - mm->context.size = 0; - } + int i, nr_pages = (mm->context.size*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE; + + for (i = 0; i < nr_pages; i++) + __free_page(mm->context.ldt_pages[i]); + mm->context.size = 0; } static int read_ldt(void __user * ptr, unsigned long bytecount) { - int err; + int err, i; unsigned long size; struct mm_struct * mm = current->mm; @@ -138,8 +135,25 @@ size = bytecount; err = 0; - if (copy_to_user(ptr, mm->context.ldt, size)) - err = -EFAULT; + /* + * This is necessary just in case we got here straight from a + * context-switch where the ptes were set but no tlb flush + * was done yet. We rather avoid doing a TLB flush in the + * context-switch path and do it here instead. + */ + __flush_tlb_global(); + + for (i = 0; i < size; i += PAGE_SIZE) { + int nr = i / PAGE_SIZE, bytes; + char *kaddr = kmap(mm->context.ldt_pages[nr]); + + bytes = size - i; + if (bytes > PAGE_SIZE) + bytes = PAGE_SIZE; + if (copy_to_user(ptr + i, kaddr, size - i)) + err = -EFAULT; + kunmap(mm->context.ldt_pages[nr]); + } up(&mm->context.sem); if (err < 0) return err; @@ -158,7 +172,7 @@ err = 0; address = &default_ldt[0]; - size = 5*sizeof(struct desc_struct); + size = 5*LDT_ENTRY_SIZE; if (size > bytecount) size = bytecount; @@ -200,7 +214,15 @@ goto out_unlock; } - lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt); + /* + * No rescheduling allowed from this point to the install. + * + * We do a TLB flush for the same reason as in the read_ldt() path. + */ + preempt_disable(); + __flush_tlb_global(); + lp = (__u32 *) ((ldt_info.entry_number << 3) + + (char *) __kmap_atomic_vaddr(KM_LDT_PAGE0)); /* Allow LDTs to be cleared by the user. */ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { @@ -221,6 +243,7 @@ *lp = entry_1; *(lp+1) = entry_2; error = 0; + preempt_enable(); out_unlock: up(&mm->context.sem); @@ -248,3 +271,26 @@ } return ret; } + +/* + * load one particular LDT into the current CPU + */ +void load_LDT_nolock(mm_context_t *pc, int cpu) +{ + struct page **pages = pc->ldt_pages; + int count = pc->size; + int nr_pages, i; + + if (likely(!count)) { + pages = &default_ldt_page; + count = 5; + } + nr_pages = (count*LDT_ENTRY_SIZE + PAGE_SIZE-1) / PAGE_SIZE; + + for (i = 0; i < nr_pages; i++) { + __kunmap_atomic_type(KM_LDT_PAGE0 - i); + __kmap_atomic(pages[i], KM_LDT_PAGE0 - i); + } + set_ldt_desc(cpu, (void *)__kmap_atomic_vaddr(KM_LDT_PAGE0), count); + load_LDT_desc(); +} --- diff/arch/i386/kernel/microcode.c 2003-10-27 09:20:43.000000000 +0000 +++ source/arch/i386/kernel/microcode.c 2004-02-09 10:39:50.000000000 +0000 @@ -507,3 +507,4 @@ module_init(microcode_init) module_exit(microcode_exit) +MODULE_ALIAS_MISCDEV(MICROCODE_MINOR); --- diff/arch/i386/kernel/mpparse.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/i386/kernel/mpparse.c 2004-02-09 10:39:50.000000000 +0000 @@ -668,7 +668,7 @@ * Read the physical hardware table. Anything here will * override the defaults. */ - if (!smp_read_mpc((void *)mpf->mpf_physptr)) { + if (!smp_read_mpc((void *)phys_to_virt(mpf->mpf_physptr))) { smp_found_config = 0; printk(KERN_ERR "BIOS bug, MP table errors detected!...\n"); printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n"); @@ -1126,7 +1126,8 @@ /* Don't set up the ACPI SCI because it's already set up */ if (acpi_fadt.sci_int == irq) { - entry->irq = irq; /*we still need to set entry's irq*/ + irq = acpi_irq_to_vector(irq); + entry->irq = irq; /* we still need to set entry's irq */ continue; } @@ -1156,18 +1157,14 @@ if ((1<irq = irq; + entry->irq = acpi_irq_to_vector(irq); continue; } mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<irq = irq; + entry->irq = acpi_irq_to_vector(irq); } printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n", entry->id.segment, entry->id.bus, --- diff/arch/i386/kernel/msr.c 2003-09-17 12:28:01.000000000 +0100 +++ source/arch/i386/kernel/msr.c 2004-02-09 10:39:50.000000000 +0000 @@ -1,4 +1,3 @@ -#ident "$Id$" /* ----------------------------------------------------------------------- * * * Copyright 2000 H. Peter Anvin - All Rights Reserved --- diff/arch/i386/kernel/nmi.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/kernel/nmi.c 2004-02-09 10:39:50.000000000 +0000 @@ -31,7 +31,16 @@ #include #include +#ifdef CONFIG_KGDB +#include +#ifdef CONFIG_SMP +unsigned int nmi_watchdog = NMI_IO_APIC; +#else +unsigned int nmi_watchdog = NMI_LOCAL_APIC; +#endif +#else unsigned int nmi_watchdog = NMI_NONE; +#endif static unsigned int nmi_hz = HZ; unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ extern void show_registers(struct pt_regs *regs); @@ -408,6 +417,9 @@ for (i = 0; i < NR_CPUS; i++) alert_counter[i] = 0; } +#ifdef CONFIG_KGDB +int tune_watchdog = 5*HZ; +#endif void nmi_watchdog_tick (struct pt_regs * regs) { @@ -421,12 +433,24 @@ sum = irq_stat[cpu].apic_timer_irqs; +#ifdef CONFIG_KGDB + if (! in_kgdb(regs) && last_irq_sums[cpu] == sum ) { + +#else if (last_irq_sums[cpu] == sum) { +#endif /* * Ayiee, looks like this CPU is stuck ... * wait a few IRQs (5 seconds) before doing the oops ... */ alert_counter[cpu]++; +#ifdef CONFIG_KGDB + if (alert_counter[cpu] == tune_watchdog) { + kgdb_handle_exception(2, SIGPWR, 0, regs); + last_irq_sums[cpu] = sum; + alert_counter[cpu] = 0; + } +#endif if (alert_counter[cpu] == 5*nmi_hz) { spin_lock(&nmi_print_lock); /* --- diff/arch/i386/kernel/process.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/i386/kernel/process.c 2004-02-09 10:39:50.000000000 +0000 @@ -14,6 +14,7 @@ #define __KERNEL_SYSCALLS__ #include +#include #include #include #include @@ -47,6 +48,7 @@ #include #include #include +#include #ifdef CONFIG_MATH_EMULATION #include #endif @@ -54,6 +56,9 @@ #include #include +#include +#include + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); int hlt_counter; @@ -132,6 +137,60 @@ } } +#ifdef CONFIG_HOTPLUG_CPU + +/* We don't actually take CPU down, just spin without interrupts. */ +static inline void check_cpu_quiescent(void) +{ + if (unlikely(__get_cpu_var(cpu_state) == CPU_OFFLINE)) { + int cpu = smp_processor_id(); + + spin_lock(&call_lock); + local_irq_disable(); + preempt_disable(); + + /* Ack it */ + __get_cpu_var(cpu_state) = CPU_DEAD; + + BUG_ON(cpu_isset(cpu, cpu_online_map)); + BUG_ON(!cpu_isset(cpu, cpu_active_map)); + cpu_clear(cpu, cpu_active_map); + spin_unlock(&call_lock); + + /* Death loop */ + while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) + cpu_relax(); + + /* Even with irqs disabled, this is safe, since no + * smp_call_funcion can be headed for us now + * (!cpu_active). */ + spin_lock(&call_lock); + + /* from hereon we're ready to do work */ + __get_cpu_var(cpu_state) = CPU_ONLINE; + wmb(); + + //printk("Cpu %u arisen\n", smp_processor_id()); + + /* Put ourselves online before doing ___flush_tlb_all, + * so we avoid losing one to a race. */ + cpu_set(smp_processor_id(), cpu_active_map); + cpu_set(smp_processor_id(), cpu_online_map); + wmb(); + spin_unlock(&call_lock); + + __flush_tlb_all(); + local_irq_enable(); + + preempt_enable(); + } +} +#else +static inline void check_cpu_quiescent(void) +{ +} +#endif /* CONFIG_HOTPLUG_CPU */ + /* * The idle thread. There's no useful work to be * done, so just try to conserve power and have a @@ -148,6 +207,7 @@ if (!idle) idle = default_idle; + check_cpu_quiescent(); irq_stat[smp_processor_id()].idle_timestamp = jiffies; idle(); } @@ -252,13 +312,15 @@ * the "args". */ extern void kernel_thread_helper(void); -__asm__(".align 4\n" +__asm__(".section .text\n" + ".align 4\n" "kernel_thread_helper:\n\t" "movl %edx,%eax\n\t" "pushl %edx\n\t" "call *%ebx\n\t" "pushl %eax\n\t" - "call do_exit"); + "call do_exit\n" + ".previous"); /* * Create a kernel thread @@ -302,6 +364,9 @@ struct task_struct *tsk = current; memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); +#ifdef CONFIG_X86_HIGH_ENTRY + clear_thread_flag(TIF_DB7); +#endif memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); /* * Forget coprocessor state.. @@ -315,9 +380,8 @@ if (dead_task->mm) { // temporary debugging check if (dead_task->mm->context.size) { - printk("WARNING: dead process %8s still has LDT? <%p/%d>\n", + printk("WARNING: dead process %8s still has LDT? <%d>\n", dead_task->comm, - dead_task->mm->context.ldt, dead_task->mm->context.size); BUG(); } @@ -352,7 +416,17 @@ p->thread.esp = (unsigned long) childregs; p->thread.esp0 = (unsigned long) (childregs+1); + /* + * get the two stack pages, for the virtual stack. + * + * IMPORTANT: this code relies on the fact that the task + * structure is an 8K aligned piece of physical memory. + */ + p->thread.stack_page0 = virt_to_page((unsigned long)p->thread_info); + p->thread.stack_page1 = virt_to_page((unsigned long)p->thread_info + PAGE_SIZE); + p->thread.eip = (unsigned long) ret_from_fork; + p->thread_info->real_stack = p->thread_info; savesegment(fs,p->thread.fs); savesegment(gs,p->thread.gs); @@ -504,10 +578,41 @@ __unlazy_fpu(prev_p); +#ifdef CONFIG_X86_HIGH_ENTRY + /* + * Set the ptes of the virtual stack. (NOTE: a one-page TLB flush is + * needed because otherwise NMIs could interrupt the + * user-return code with a virtual stack and stale TLBs.) + */ + __kunmap_atomic_type(KM_VSTACK0); + __kunmap_atomic_type(KM_VSTACK1); + __kmap_atomic(next->stack_page0, KM_VSTACK0); + __kmap_atomic(next->stack_page1, KM_VSTACK1); + + /* + * NOTE: here we rely on the task being the stack as well + */ + next_p->thread_info->virtual_stack = + (void *)__kmap_atomic_vaddr(KM_VSTACK0); + +#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) + /* + * If next was preempted on entry from userspace to kernel, + * and now it's on a different cpu, we need to adjust %esp. + * This assumes that entry.S does not copy %esp while on the + * virtual stack (with interrupts enabled): which is so, + * except within __SWITCH_KERNELSPACE itself. + */ + if (unlikely(next->esp >= TASK_SIZE)) { + next->esp &= THREAD_SIZE - 1; + next->esp |= (unsigned long) next_p->thread_info->virtual_stack; + } +#endif +#endif /* * Reload esp0, LDT and the page table pointer: */ - load_esp0(tss, next); + load_virtual_esp0(tss, next_p); /* * Load the per-thread Thread-Local Storage descriptor. --- diff/arch/i386/kernel/reboot.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/i386/kernel/reboot.c 2004-02-09 10:39:50.000000000 +0000 @@ -155,12 +155,11 @@ CMOS_WRITE(0x00, 0x8f); spin_unlock_irqrestore(&rtc_lock, flags); - /* Remap the kernel at virtual address zero, as well as offset zero - from the kernel segment. This assumes the kernel segment starts at - virtual address PAGE_OFFSET. */ - - memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, - sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); + /* + * Remap the first 16 MB of RAM (which includes the kernel image) + * at virtual address zero: + */ + setup_identity_mappings(swapper_pg_dir, 0, 16*1024*1024); /* * Use `swapper_pg_dir' as our page directory. --- diff/arch/i386/kernel/setup.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/i386/kernel/setup.c 2004-02-09 10:39:50.000000000 +0000 @@ -444,6 +444,12 @@ #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) unsigned char eddnr; struct edd_info edd[EDDMAXNR]; +unsigned int edd_disk80_sig; +#ifdef CONFIG_EDD_MODULE +EXPORT_SYMBOL(eddnr); +EXPORT_SYMBOL(edd); +EXPORT_SYMBOL(edd_disk80_sig); +#endif /** * copy_edd() - Copy the BIOS EDD information * from empty_zero_page into a safe place. @@ -453,6 +459,7 @@ { eddnr = EDD_NR; memcpy(edd, EDD_BUF, sizeof(edd)); + edd_disk80_sig = DISK80_SIGNATURE; } #else #define copy_edd() do {} while (0) --- diff/arch/i386/kernel/signal.c 2003-11-25 15:24:57.000000000 +0000 +++ source/arch/i386/kernel/signal.c 2004-02-09 10:39:50.000000000 +0000 @@ -128,28 +128,29 @@ */ static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax) +restore_sigcontext(struct pt_regs *regs, + struct sigcontext __user *__sc, int *peax) { - unsigned int err = 0; + struct sigcontext scratch; /* 88 bytes of scratch area */ /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; -#define COPY(x) err |= __get_user(regs->x, &sc->x) + if (copy_from_user(&scratch, __sc, sizeof(scratch))) + return -EFAULT; + +#define COPY(x) regs->x = scratch.x #define COPY_SEG(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ regs->x##seg = tmp; } #define COPY_SEG_STRICT(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ regs->x##seg = tmp|3; } #define GET_SEG(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp = scratch.seg; \ loadsegment(seg,tmp); } GET_SEG(gs); @@ -168,27 +169,23 @@ COPY_SEG_STRICT(ss); { - unsigned int tmpflags; - err |= __get_user(tmpflags, &sc->eflags); + unsigned int tmpflags = scratch.eflags; regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); regs->orig_eax = -1; /* disable syscall checks */ } { - struct _fpstate __user * buf; - err |= __get_user(buf, &sc->fpstate); + struct _fpstate * buf = scratch.fpstate; if (buf) { if (verify_area(VERIFY_READ, buf, sizeof(*buf))) - goto badframe; - err |= restore_i387(buf); + return -EFAULT; + if (restore_i387(buf)) + return -EFAULT; } } - err |= __get_user(*peax, &sc->eax); - return err; - -badframe: - return 1; + *peax = scratch.eax; + return 0; } asmlinkage int sys_sigreturn(unsigned long __unused) @@ -266,46 +263,47 @@ */ static int -setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, +setup_sigcontext(struct sigcontext __user *__sc, struct _fpstate __user *fpstate, struct pt_regs *regs, unsigned long mask) { - int tmp, err = 0; + struct sigcontext sc; /* 88 bytes of scratch area */ + int tmp; tmp = 0; __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp)); - err |= __put_user(tmp, (unsigned int *)&sc->gs); + *(unsigned int *)&sc.gs = tmp; __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp)); - err |= __put_user(tmp, (unsigned int *)&sc->fs); - - err |= __put_user(regs->xes, (unsigned int *)&sc->es); - err |= __put_user(regs->xds, (unsigned int *)&sc->ds); - err |= __put_user(regs->edi, &sc->edi); - err |= __put_user(regs->esi, &sc->esi); - err |= __put_user(regs->ebp, &sc->ebp); - err |= __put_user(regs->esp, &sc->esp); - err |= __put_user(regs->ebx, &sc->ebx); - err |= __put_user(regs->edx, &sc->edx); - err |= __put_user(regs->ecx, &sc->ecx); - err |= __put_user(regs->eax, &sc->eax); - err |= __put_user(current->thread.trap_no, &sc->trapno); - err |= __put_user(current->thread.error_code, &sc->err); - err |= __put_user(regs->eip, &sc->eip); - err |= __put_user(regs->xcs, (unsigned int *)&sc->cs); - err |= __put_user(regs->eflags, &sc->eflags); - err |= __put_user(regs->esp, &sc->esp_at_signal); - err |= __put_user(regs->xss, (unsigned int *)&sc->ss); + *(unsigned int *)&sc.fs = tmp; + *(unsigned int *)&sc.es = regs->xes; + *(unsigned int *)&sc.ds = regs->xds; + sc.edi = regs->edi; + sc.esi = regs->esi; + sc.ebp = regs->ebp; + sc.esp = regs->esp; + sc.ebx = regs->ebx; + sc.edx = regs->edx; + sc.ecx = regs->ecx; + sc.eax = regs->eax; + sc.trapno = current->thread.trap_no; + sc.err = current->thread.error_code; + sc.eip = regs->eip; + *(unsigned int *)&sc.cs = regs->xcs; + sc.eflags = regs->eflags; + sc.esp_at_signal = regs->esp; + *(unsigned int *)&sc.ss = regs->xss; tmp = save_i387(fpstate); if (tmp < 0) - err = 1; - else - err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); + return 1; + sc.fpstate = tmp ? fpstate : NULL; /* non-iBCS2 extensions.. */ - err |= __put_user(mask, &sc->oldmask); - err |= __put_user(current->thread.cr2, &sc->cr2); + sc.oldmask = mask; + sc.cr2 = current->thread.cr2; - return err; + if (copy_to_user(__sc, &sc, sizeof(sc))) + return 1; + return 0; } /* @@ -443,7 +441,7 @@ /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(current->sas_ss_sp, (unsigned long *)&frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->esp), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); --- diff/arch/i386/kernel/smp.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/kernel/smp.c 2004-02-09 10:39:50.000000000 +0000 @@ -327,10 +327,12 @@ if (flush_mm == cpu_tlbstate[cpu].active_mm) { if (cpu_tlbstate[cpu].state == TLBSTATE_OK) { +#ifndef CONFIG_X86_SWITCH_PAGETABLES if (flush_va == FLUSH_ALL) local_flush_tlb(); else __flush_tlb_one(flush_va); +#endif } else leave_mm(cpu); } @@ -355,11 +357,15 @@ */ BUG_ON(cpus_empty(cpumask)); - cpus_and(tmp, cpumask, cpu_online_map); + cpus_and(tmp, cpumask, cpu_callout_map); BUG_ON(!cpus_equal(cpumask, tmp)); BUG_ON(cpu_isset(smp_processor_id(), cpumask)); BUG_ON(!mm); + cpus_and(cpumask, cpumask, cpu_active_map); + if (cpus_empty(cpumask)) + return; + /* * i'm not happy about this global shared spinlock in the * MM hot path, but we'll see how contended it is. @@ -387,30 +393,17 @@ */ send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR); - while (!cpus_empty(flush_cpumask)) - /* nothing. lockup detection does not belong here */ + do { mb(); + tmp = flush_cpumask; + cpus_and(tmp, tmp, cpu_active_map); + } while (!cpus_empty(tmp)); flush_mm = NULL; flush_va = 0; spin_unlock(&tlbstate_lock); } -void flush_tlb_current_task(void) -{ - struct mm_struct *mm = current->mm; - cpumask_t cpu_mask; - - preempt_disable(); - cpu_mask = mm->cpu_vm_mask; - cpu_clear(smp_processor_id(), cpu_mask); - - local_flush_tlb(); - if (!cpus_empty(cpu_mask)) - flush_tlb_others(cpu_mask, mm, FLUSH_ALL); - preempt_enable(); -} - void flush_tlb_mm (struct mm_struct * mm) { cpumask_t cpu_mask; @@ -442,7 +435,10 @@ if (current->active_mm == mm) { if(current->mm) - __flush_tlb_one(va); +#ifndef CONFIG_X86_SWITCH_PAGETABLES + __flush_tlb_one(va) +#endif + ; else leave_mm(smp_processor_id()); } @@ -466,7 +462,17 @@ { on_each_cpu(do_flush_tlb_all, 0, 1, 1); } - +#ifdef CONFIG_KGDB +/* + * By using the NMI code instead of a vector we just sneak thru the + * word generator coming out with just what we want. AND it does + * not matter if clustered_apic_mode is set or not. + */ +void smp_send_nmi_allbutself(void) +{ + send_IPI_allbutself(APIC_DM_NMI); +} +#endif /* * this function sends a 'reschedule' IPI to another CPU. * it goes straight through and wastes no time serializing @@ -481,13 +487,13 @@ * Structure and data for smp_call_function(). This is designed to minimise * static memory requirements. It also looks cleaner. */ -static spinlock_t call_lock = SPIN_LOCK_UNLOCKED; +spinlock_t call_lock = SPIN_LOCK_UNLOCKED; struct call_data_struct { void (*func) (void *info); void *info; - atomic_t started; - atomic_t finished; + cpumask_t not_started; + cpumask_t not_finished; int wait; }; @@ -514,32 +520,44 @@ */ { struct call_data_struct data; - int cpus = num_online_cpus()-1; + cpumask_t mask; + int cpu; - if (!cpus) - return 0; + spin_lock(&call_lock); + cpu = smp_processor_id(); data.func = func; data.info = info; - atomic_set(&data.started, 0); + data.not_started = cpu_active_map; + cpu_clear(cpu, data.not_started); + if (cpus_empty(data.not_started)) + goto out_unlock; + data.wait = wait; if (wait) - atomic_set(&data.finished, 0); + data.not_finished = data.not_started; - spin_lock(&call_lock); call_data = &data; mb(); /* Send a message to all other CPUs and wait for them to respond */ - send_IPI_allbutself(CALL_FUNCTION_VECTOR); + send_IPI_mask(data.not_started, CALL_FUNCTION_VECTOR); /* Wait for response */ - while (atomic_read(&data.started) != cpus) - barrier(); + do { + mb(); + mask = data.not_started; + cpus_and(mask, mask, cpu_active_map); + } while(!cpus_empty(mask)); if (wait) - while (atomic_read(&data.finished) != cpus) - barrier(); + do { + mb(); + mask = data.not_finished; + cpus_and(mask, mask, cpu_active_map); + } while(!cpus_empty(mask)); + +out_unlock: spin_unlock(&call_lock); return 0; @@ -551,6 +569,7 @@ * Remove this CPU: */ cpu_clear(smp_processor_id(), cpu_online_map); + cpu_clear(smp_processor_id(), cpu_active_map); local_irq_disable(); disable_local_APIC(); if (cpu_data[smp_processor_id()].hlt_works_ok) @@ -583,17 +602,25 @@ asmlinkage void smp_call_function_interrupt(void) { - void (*func) (void *info) = call_data->func; - void *info = call_data->info; - int wait = call_data->wait; + void (*func) (void *info); + void *info; + int wait; + int cpu = smp_processor_id(); ack_APIC_irq(); + + func = call_data->func; + info = call_data->info; + wait = call_data->wait; + /* * Notify initiating CPU that I've grabbed the data and am * about to execute the function */ - mb(); - atomic_inc(&call_data->started); + smp_mb__before_clear_bit(); + cpu_clear(cpu, call_data->not_started); + smp_mb__after_clear_bit(); + /* * At this point the info structure may be out of scope unless wait==1 */ @@ -602,8 +629,9 @@ irq_exit(); if (wait) { - mb(); - atomic_inc(&call_data->finished); + smp_mb__before_clear_bit(); + cpu_clear(cpu, call_data->not_finished); + smp_mb__after_clear_bit(); } } --- diff/arch/i386/kernel/smpboot.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/i386/kernel/smpboot.c 2004-02-09 10:39:50.000000000 +0000 @@ -33,15 +33,20 @@ * Dave Jones : Report invalid combinations of Athlon CPUs. * Rusty Russell : Hacked into shape for new "hotplug" boot process. */ +#include #include #include #include #include +#include #include #include #include #include +#include +#include +#include #include #include @@ -64,7 +69,12 @@ /* bitmap of online cpus */ cpumask_t cpu_online_map; -static cpumask_t cpu_callin_map; +#ifdef CONFIG_HOTPLUG_CPU +cpumask_t cpu_active_map; +#endif + +/* Initialize, although master cpu never calls in */ +static volatile cpumask_t cpu_callin_map; cpumask_t cpu_callout_map; static cpumask_t smp_commenced_mask; @@ -82,6 +92,9 @@ extern unsigned char trampoline_end []; static unsigned char *trampoline_base; +/* State of each CPU. */ +DEFINE_PER_CPU(int, cpu_state) = { 0 }; + /* * Currently trivial. Write the real->protected mode * bootstrap into the page concerned. The caller @@ -456,7 +469,9 @@ * the local TLBs too. */ local_flush_tlb(); + /* cpu_set should suffice for this stage of bootup -zwane*/ cpu_set(smp_processor_id(), cpu_online_map); + cpu_set(smp_processor_id(), cpu_active_map); wmb(); return cpu_idle(); } @@ -503,6 +518,7 @@ { [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE }; /* which node each logical CPU is on */ int cpu_2_node[NR_CPUS] = { [0 ... NR_CPUS-1] = 0 }; +EXPORT_SYMBOL(cpu_2_node); /* set up a mapping between cpu and node. */ static inline void map_cpu_to_node(int cpu, int node) @@ -932,7 +948,7 @@ /* Where the IO area was mapped on multiquad, always 0 otherwise */ void *xquad_portio; -int cpu_sibling_map[NR_CPUS] __cacheline_aligned; +cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned; static void __init smp_boot_cpus(unsigned int max_cpus) { @@ -950,6 +966,8 @@ current_thread_info()->cpu = 0; smp_tune_scheduling(); + cpus_clear(cpu_sibling_map[0]); + cpu_set(0, cpu_sibling_map[0]); /* * If we couldn't find an SMP configuration at boot time, @@ -1078,32 +1096,34 @@ Dprintk("Boot done.\n"); /* - * If Hyper-Threading is avaialble, construct cpu_sibling_map[], so - * that we can tell the sibling CPU efficiently. + * construct cpu_sibling_map[], so that we can tell sibling CPUs + * efficiently. */ - if (cpu_has_ht && smp_num_siblings > 1) { - for (cpu = 0; cpu < NR_CPUS; cpu++) - cpu_sibling_map[cpu] = NO_PROC_ID; - - for (cpu = 0; cpu < NR_CPUS; cpu++) { - int i; - if (!cpu_isset(cpu, cpu_callout_map)) - continue; + for (cpu = 0; cpu < NR_CPUS; cpu++) + cpus_clear(cpu_sibling_map[cpu]); + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + int siblings = 0; + int i; + if (!cpu_isset(cpu, cpu_callout_map)) + continue; + if (smp_num_siblings > 1) { for (i = 0; i < NR_CPUS; i++) { - if (i == cpu || !cpu_isset(i, cpu_callout_map)) + if (!cpu_isset(i, cpu_callout_map)) continue; if (phys_proc_id[cpu] == phys_proc_id[i]) { - cpu_sibling_map[cpu] = i; - printk("cpu_sibling_map[%d] = %d\n", cpu, cpu_sibling_map[cpu]); - break; + siblings++; + cpu_set(i, cpu_sibling_map[cpu]); } } - if (cpu_sibling_map[cpu] == NO_PROC_ID) { - smp_num_siblings = 1; - printk(KERN_WARNING "WARNING: No sibling found for CPU %d.\n", cpu); - } + } else { + siblings++; + cpu_set(cpu, cpu_sibling_map[cpu]); } + + if (siblings != smp_num_siblings) + printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings); } smpboot_setup_io_apic(); @@ -1117,33 +1137,325 @@ synchronize_tsc_bp(); } +#ifdef CONFIG_SCHED_SMT +#ifdef CONFIG_NUMA +static struct sched_group sched_group_cpus[NR_CPUS]; +static struct sched_group sched_group_phys[NR_CPUS]; +static struct sched_group sched_group_nodes[MAX_NUMNODES]; +static DEFINE_PER_CPU(struct sched_domain, phys_domains); +static DEFINE_PER_CPU(struct sched_domain, node_domains); +__init void arch_init_sched_domains(void) +{ + int i; + struct sched_group *first_cpu = NULL, *last_cpu = NULL; + + /* Set up domains */ + for_each_cpu_mask(i, cpu_online_map) { + struct sched_domain *cpu_domain = cpu_sched_domain(i); + struct sched_domain *phys_domain = &per_cpu(phys_domains, i); + struct sched_domain *node_domain = &per_cpu(node_domains, i); + int node = cpu_to_node(i); + cpumask_t nodemask = node_to_cpumask(node); + + *cpu_domain = SD_SIBLING_INIT; + cpu_domain->span = cpu_sibling_map[i]; + + *phys_domain = SD_CPU_INIT; + phys_domain->span = nodemask; + phys_domain->flags |= SD_FLAG_IDLE; + + *node_domain = SD_NODE_INIT; + node_domain->span = cpu_online_map; + } + + /* Set up CPU (sibling) groups */ + for_each_cpu_mask(i, cpu_online_map) { + struct sched_domain *cpu_domain = cpu_sched_domain(i); + int j; + first_cpu = last_cpu = NULL; + + if (i != first_cpu(cpu_domain->span)) + continue; + + for_each_cpu_mask(j, cpu_domain->span) { + struct sched_group *cpu = &sched_group_cpus[j]; + + cpu->cpumask = CPU_MASK_NONE; + cpu_set(j, cpu->cpumask); + + if (!first_cpu) + first_cpu = cpu; + if (last_cpu) + last_cpu->next = cpu; + last_cpu = cpu; + } + last_cpu->next = first_cpu; + } + + for (i = 0; i < MAX_NUMNODES; i++) { + int j; + cpumask_t nodemask; + cpus_and(nodemask, node_to_cpumask(i), cpu_online_map); + + first_cpu = last_cpu = NULL; + /* Set up physical groups */ + for_each_cpu_mask(j, nodemask) { + struct sched_domain *cpu_domain = cpu_sched_domain(j); + struct sched_group *cpu = &sched_group_phys[j]; + + if (j != first_cpu(cpu_domain->span)) + continue; + + cpu->cpumask = cpu_domain->span; + + if (!first_cpu) + first_cpu = cpu; + if (last_cpu) + last_cpu->next = cpu; + last_cpu = cpu; + } + last_cpu->next = first_cpu; + } + + /* Set up nodes */ + first_cpu = last_cpu = NULL; + for (i = 0; i < MAX_NUMNODES; i++) { + struct sched_group *cpu = &sched_group_nodes[i]; + cpumask_t nodemask; + cpus_and(nodemask, node_to_cpumask(i), cpu_online_map); + + if (cpus_empty(nodemask)) + continue; + + cpu->cpumask = nodemask; + + if (!first_cpu) + first_cpu = cpu; + if (last_cpu) + last_cpu->next = cpu; + last_cpu = cpu; + } + last_cpu->next = first_cpu; + + + mb(); + for_each_cpu_mask(i, cpu_online_map) { + int node = cpu_to_node(i); + struct sched_domain *cpu_domain = cpu_sched_domain(i); + struct sched_domain *phys_domain = &per_cpu(phys_domains, i); + struct sched_domain *node_domain = &per_cpu(node_domains, i); + struct sched_group *cpu_group = &sched_group_cpus[i]; + struct sched_group *phys_group = &sched_group_phys[first_cpu(cpu_domain->span)]; + struct sched_group *node_group = &sched_group_nodes[node]; + + cpu_domain->parent = phys_domain; + phys_domain->parent = node_domain; + + node_domain->groups = node_group; + phys_domain->groups = phys_group; + cpu_domain->groups = cpu_group; + } +} +#else /* CONFIG_NUMA */ +static struct sched_group sched_group_cpus[NR_CPUS]; +static struct sched_group sched_group_phys[NR_CPUS]; +static DEFINE_PER_CPU(struct sched_domain, phys_domains); +__init void arch_init_sched_domains(void) +{ + int i; + struct sched_group *first_cpu = NULL, *last_cpu = NULL; + + /* Set up domains */ + for_each_cpu_mask(i, cpu_online_map) { + struct sched_domain *cpu_domain = cpu_sched_domain(i); + struct sched_domain *phys_domain = &per_cpu(phys_domains, i); + + *cpu_domain = SD_SIBLING_INIT; + cpu_domain->span = cpu_sibling_map[i]; + + *phys_domain = SD_CPU_INIT; + phys_domain->span = cpu_online_map; + phys_domain->flags |= SD_FLAG_IDLE; + } + + /* Set up CPU (sibling) groups */ + for_each_cpu_mask(i, cpu_online_map) { + struct sched_domain *cpu_domain = cpu_sched_domain(i); + int j; + first_cpu = last_cpu = NULL; + + if (i != first_cpu(cpu_domain->span)) + continue; + + for_each_cpu_mask(j, cpu_domain->span) { + struct sched_group *cpu = &sched_group_cpus[j]; + + cpus_clear(cpu->cpumask); + cpu_set(j, cpu->cpumask); + + if (!first_cpu) + first_cpu = cpu; + if (last_cpu) + last_cpu->next = cpu; + last_cpu = cpu; + } + last_cpu->next = first_cpu; + } + + first_cpu = last_cpu = NULL; + /* Set up physical groups */ + for_each_cpu_mask(i, cpu_online_map) { + struct sched_domain *cpu_domain = cpu_sched_domain(i); + struct sched_group *cpu = &sched_group_phys[i]; + + if (i != first_cpu(cpu_domain->span)) + continue; + + cpu->cpumask = cpu_domain->span; + + if (!first_cpu) + first_cpu = cpu; + if (last_cpu) + last_cpu->next = cpu; + last_cpu = cpu; + } + last_cpu->next = first_cpu; + + mb(); + for_each_cpu_mask(i, cpu_online_map) { + struct sched_domain *cpu_domain = cpu_sched_domain(i); + struct sched_domain *phys_domain = &per_cpu(phys_domains, i); + struct sched_group *cpu_group = &sched_group_cpus[i]; + struct sched_group *phys_group = &sched_group_phys[first_cpu(cpu_domain->span)]; + cpu_domain->parent = phys_domain; + phys_domain->groups = phys_group; + cpu_domain->groups = cpu_group; + } +} +#endif /* CONFIG_NUMA */ +#endif /* CONFIG_SCHED_SMT */ + /* These are wrappers to interface to the new boot process. Someone who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */ void __init smp_prepare_cpus(unsigned int max_cpus) { + smp_commenced_mask = cpumask_of_cpu(0); + cpu_callin_map = cpumask_of_cpu(0); + mb(); smp_boot_cpus(max_cpus); } void __devinit smp_prepare_boot_cpu(void) { cpu_set(smp_processor_id(), cpu_online_map); + cpu_set(smp_processor_id(), cpu_active_map); cpu_set(smp_processor_id(), cpu_callout_map); } +#ifdef CONFIG_HOTPLUG_CPU +/* must be called with the cpucontrol mutex held */ +static int __devinit cpu_enable(unsigned int cpu) +{ + /* get the target out of it's holding state */ + per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; + wmb(); + + /* wait for the processor to ack it. timeout? */ + while (!cpu_online(cpu)) + cpu_relax(); + return 0; +} + +int __cpu_disable(void) +{ + int cpu = smp_processor_id(); + /* + * Nothing for now, perhaps use cpufreq to drop frequency, + * but that could go into generic code. + * + * We won't take down the boot processor on i386 due to some + * interrupts only being able to be serviced by the BSP. + * Especially so if we're not using an IOAPIC -zwane + */ + if (cpu == 0) + return -EBUSY; + + BUG_ON(!cpu_isset(cpu, cpu_active_map)); + BUG_ON(!cpu_isset(cpu, cpu_online_map)); + wmb(); + cpu_clear(cpu, cpu_online_map); + wmb(); + + return 0; +} + +static void do_nothing(void *unused) +{ + return; +} + +void __cpu_die(unsigned int cpu) +{ + unsigned int i; + + /* Final threads can take some time to actually clean up */ + while (!idle_cpu(cpu)) + yield(); + + per_cpu(cpu_state, cpu) = CPU_OFFLINE; + wmb(); + for (i = 0; i < 10; i++) { + wake_idle_cpu(cpu); + /* They ack this in check_cpu_quiescent by setting CPU_DEAD */ + if (per_cpu(cpu_state, cpu) == CPU_DEAD) { + /* + * This prevents a race in smp_call_function due + * to the rapid online of the same CPU which just died. + */ + smp_call_function(do_nothing, NULL, 1, 1); + return; + } + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); + } + printk(KERN_ERR "CPU %u didn't die...\n", cpu); +} +#else /* ... !CONFIG_HOTPLUG_CPU */ +int __cpu_disable(void) +{ + return -ENOSYS; +} + +void __cpu_die(unsigned int cpu) +{ + /* We said "no" in __cpu_disable */ + BUG(); +} +#endif /* CONFIG_HOTPLUG_CPU */ + int __devinit __cpu_up(unsigned int cpu) { /* This only works at boot for x86. See "rewrite" above. */ - if (cpu_isset(cpu, smp_commenced_mask)) { + if (cpu_isset(cpu, smp_commenced_mask) && cpu_online(cpu)) { local_irq_enable(); return -ENOSYS; } /* In case one didn't come up */ if (!cpu_isset(cpu, cpu_callin_map)) { + printk(KERN_DEBUG "skipping cpu%d, didn't come online\n", cpu); local_irq_enable(); return -EIO; } +#ifdef CONFIG_HOTPLUG_CPU + /* Already up, and in cpu_quiescent now? */ + if (cpu_isset(cpu, smp_commenced_mask)) { + cpu_enable(cpu); + /* we can simply fall through */ + } +#endif + local_irq_enable(); /* Unleash the CPU! */ cpu_set(cpu, smp_commenced_mask); --- diff/arch/i386/kernel/sysenter.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/kernel/sysenter.c 2004-02-09 10:39:50.000000000 +0000 @@ -18,13 +18,18 @@ #include #include #include +#include extern asmlinkage void sysenter_entry(void); void enable_sep_cpu(void *info) { int cpu = get_cpu(); +#ifdef CONFIG_X86_HIGH_ENTRY + struct tss_struct *tss = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu; +#else struct tss_struct *tss = init_tss + cpu; +#endif tss->ss1 = __KERNEL_CS; tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss; --- diff/arch/i386/kernel/timers/Makefile 2003-09-30 15:46:11.000000000 +0100 +++ source/arch/i386/kernel/timers/Makefile 2004-02-09 10:39:50.000000000 +0000 @@ -6,3 +6,4 @@ obj-$(CONFIG_X86_CYCLONE_TIMER) += timer_cyclone.o obj-$(CONFIG_HPET_TIMER) += timer_hpet.o +obj-$(CONFIG_X86_PM_TIMER) += timer_pm.o --- diff/arch/i386/kernel/timers/common.c 2003-09-30 15:46:11.000000000 +0100 +++ source/arch/i386/kernel/timers/common.c 2004-02-09 10:39:50.000000000 +0000 @@ -137,3 +137,23 @@ } #endif +/* calculate cpu_khz */ +void __init init_cpu_khz(void) +{ + if (cpu_has_tsc) { + unsigned long tsc_quotient = calibrate_tsc(); + if (tsc_quotient) { + /* report CPU clock rate in Hz. + * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = + * clock/second. Our precision is about 100 ppm. + */ + { unsigned long eax=0, edx=1000; + __asm__("divl %2" + :"=a" (cpu_khz), "=d" (edx) + :"r" (tsc_quotient), + "0" (eax), "1" (edx)); + printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); + } + } + } +} --- diff/arch/i386/kernel/timers/timer.c 2003-09-17 12:28:01.000000000 +0100 +++ source/arch/i386/kernel/timers/timer.c 2004-02-09 10:39:50.000000000 +0000 @@ -19,6 +19,9 @@ #ifdef CONFIG_HPET_TIMER &timer_hpet, #endif +#ifdef CONFIG_X86_PM_TIMER + &timer_pmtmr, +#endif &timer_tsc, &timer_pit, NULL, --- diff/arch/i386/kernel/timers/timer_cyclone.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/i386/kernel/timers/timer_cyclone.c 2004-02-09 10:39:50.000000000 +0000 @@ -212,26 +212,7 @@ } } - /* init cpu_khz. - * XXX - This should really be done elsewhere, - * and in a more generic fashion. -johnstul@us.ibm.com - */ - if (cpu_has_tsc) { - unsigned long tsc_quotient = calibrate_tsc(); - if (tsc_quotient) { - /* report CPU clock rate in Hz. - * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = - * clock/second. Our precision is about 100 ppm. - */ - { unsigned long eax=0, edx=1000; - __asm__("divl %2" - :"=a" (cpu_khz), "=d" (edx) - :"r" (tsc_quotient), - "0" (eax), "1" (edx)); - printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); - } - } - } + init_cpu_khz(); /* Everything looks good! */ return 0; --- diff/arch/i386/kernel/timers/timer_tsc.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/i386/kernel/timers/timer_tsc.c 2004-02-09 10:39:50.000000000 +0000 @@ -232,9 +232,13 @@ /* sanity check to ensure we're not always losing ticks */ if (lost_count++ > 100) { printk(KERN_WARNING "Losing too many ticks!\n"); - printk(KERN_WARNING "TSC cannot be used as a timesource." - " (Are you running with SpeedStep?)\n"); - printk(KERN_WARNING "Falling back to a sane timesource.\n"); + printk(KERN_WARNING "TSC cannot be used as a timesource. "); + printk(KERN_WARNING "Possible reasons for this are:\n"); + printk(KERN_WARNING " You're running with Speedstep,\n"); + printk(KERN_WARNING " You don't have DMA enabled for your hard disk (see hdparm),\n"); + printk(KERN_WARNING " Incorrect TSC synchronization on an SMP system (see dmesg).\n"); + printk(KERN_WARNING "Falling back to a sane timesource now.\n"); + clock_fallback(); } } else --- diff/arch/i386/kernel/traps.c 2003-10-27 09:20:36.000000000 +0000 +++ source/arch/i386/kernel/traps.c 2004-02-09 10:39:50.000000000 +0000 @@ -54,12 +54,8 @@ #include "mach_traps.h" -asmlinkage int system_call(void); -asmlinkage void lcall7(void); -asmlinkage void lcall27(void); - -struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, - { 0, 0 }, { 0, 0 } }; +struct desc_struct default_ldt[] __attribute__((__section__(".data.default_ldt"))) = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; +struct page *default_ldt_page; /* Do we ignore FPU interrupts ? */ char ignore_fpu_irq = 0; @@ -91,6 +87,43 @@ asmlinkage void spurious_interrupt_bug(void); asmlinkage void machine_check(void); +#ifdef CONFIG_KGDB +extern void sysenter_entry(void); +#include +#include +extern void int3(void); +extern void debug(void); +void set_intr_gate(unsigned int n, void *addr); +static void set_intr_usr_gate(unsigned int n, void *addr); +/* + * Should be able to call this breakpoint() very early in + * bring up. Just hard code the call where needed. + * The breakpoint() code is here because set_?_gate() functions + * are local (static) to trap.c. They need be done only once, + * but it does not hurt to do them over. + */ +void breakpoint(void) +{ + init_entry_mappings(); + set_intr_usr_gate(3,&int3); /* disable ints on trap */ + set_intr_gate(1,&debug); + set_intr_gate(14,&page_fault); + + BREAKPOINT; +} +#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) \ + { \ + if (!user_mode(regs) ) \ + { \ + kgdb_handle_exception(trapnr, signr, error_code, regs); \ + after; \ + } else if ((trapnr == 3) && (regs->eflags &0x200)) local_irq_enable(); \ + } +#else +#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) +#endif + + static int kstack_depth_to_print = 24; void show_trace(struct task_struct *task, unsigned long * stack) @@ -175,8 +208,9 @@ ss = regs->xss & 0xffff; } print_modules(); - printk("CPU: %d\nEIP: %04x:[<%08lx>] %s\nEFLAGS: %08lx\n", - smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags); + printk("CPU: %d\nEIP: %04x:[<%08lx>] %s VLI\nEFLAGS: %08lx\n", + smp_processor_id(), 0xffff & regs->xcs, + regs->eip, print_tainted(), regs->eflags); print_symbol("EIP is at %s\n", regs->eip); printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", @@ -192,23 +226,27 @@ * time of the fault.. */ if (in_kernel) { + u8 *eip; printk("\nStack: "); show_stack(NULL, (unsigned long*)esp); printk("Code: "); - if(regs->eip < PAGE_OFFSET) - goto bad; - for(i=0;i<20;i++) - { - unsigned char c; - if(__get_user(c, &((unsigned char*)regs->eip)[i])) { -bad: + eip = (u8 *)regs->eip - 43; + for (i = 0; i < 64; i++, eip++) { + unsigned char c = 0xff; + + if ((user_mode(regs) && get_user(c, eip)) || + (!user_mode(regs) && __direct_get_user(c, eip))) { + printk(" Bad EIP value."); break; } - printk("%02x ", c); + if (eip == (u8 *)regs->eip) + printk("<%02x> ", c); + else + printk("%02x ", c); } } printk("\n"); @@ -255,12 +293,36 @@ void die(const char * str, struct pt_regs * regs, long err) { static int die_counter; + int nl = 0; console_verbose(); spin_lock_irq(&die_lock); bust_spinlocks(1); handle_BUG(regs); printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); +#ifdef CONFIG_PREEMPT + printk("PREEMPT "); + nl = 1; +#endif +#ifdef CONFIG_SMP + printk("SMP "); + nl = 1; +#endif +#ifdef CONFIG_DEBUG_PAGEALLOC + printk("DEBUG_PAGEALLOC"); + nl = 1; +#endif + if (nl) + printk("\n"); +#ifdef CONFIG_KGDB + /* This is about the only place we want to go to kgdb even if in + * user mode. But we must go in via a trap so within kgdb we will + * always be in kernel mode. + */ + if (user_mode(regs)) + BREAKPOINT; +#endif + CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,) show_registers(regs); bust_spinlocks(0); spin_unlock_irq(&die_lock); @@ -330,6 +392,7 @@ #define DO_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,)\ do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ } @@ -347,7 +410,9 @@ #define DO_VM86_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + CHK_REMOTE_DEBUG(trapnr, signr, error_code,regs, return)\ do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ + return; \ } #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ @@ -394,8 +459,10 @@ return; gp_in_kernel: - if (!fixup_exception(regs)) + if (!fixup_exception(regs)){ + CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,) die("general protection fault", regs, error_code); + } } static void mem_parity_error(unsigned char reason, struct pt_regs * regs) @@ -534,10 +601,18 @@ if (regs->eflags & X86_EFLAGS_IF) local_irq_enable(); - /* Mask out spurious debug traps due to lazy DR7 setting */ + /* + * Mask out spurious debug traps due to lazy DR7 setting or + * due to 4G/4G kernel mode: + */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (!tsk->thread.debugreg[7]) goto clear_dr7; + if (!user_mode(regs)) { + // restore upon return-to-userspace: + set_thread_flag(TIF_DB7); + goto clear_dr7; + } } if (regs->eflags & VM_MASK) @@ -557,8 +632,18 @@ * allowing programs to debug themselves without the ptrace() * interface. */ +#ifdef CONFIG_KGDB + /* + * I think this is the only "real" case of a TF in the kernel + * that really belongs to user space. Others are + * "Ours all ours!" + */ + if (((regs->xcs & 3) == 0) && ((void *)regs->eip == sysenter_entry)) + goto clear_TF_reenable; +#else if ((regs->xcs & 3) == 0) goto clear_TF_reenable; +#endif if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE) goto clear_TF; } @@ -570,6 +655,17 @@ info.si_errno = 0; info.si_code = TRAP_BRKPT; +#ifdef CONFIG_KGDB + /* + * If this is a kernel mode trap, we need to reset db7 to allow us + * to continue sanely ALSO skip the signal delivery + */ + if ((regs->xcs & 3) == 0) + goto clear_dr7; + + /* if not kernel, allow ints but only if they were on */ + if ( regs->eflags & 0x200) local_irq_enable(); +#endif /* If this is a kernel mode trap, save the user PC on entry to * the kernel, that's what the debugger can make sense of. */ @@ -584,6 +680,7 @@ __asm__("movl %0,%%db7" : /* no output */ : "r" (0)); + CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,) return; debug_vm86: @@ -779,19 +876,53 @@ #endif /* CONFIG_MATH_EMULATION */ -#ifdef CONFIG_X86_F00F_BUG -void __init trap_init_f00f_bug(void) +void __init trap_init_virtual_IDT(void) { - __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO); - /* - * Update the IDT descriptor and reload the IDT so that - * it uses the read-only mapped virtual address. + * "idt" is magic - it overlaps the idt_descr + * variable so that updating idt will automatically + * update the idt descriptor.. */ - idt_descr.address = fix_to_virt(FIX_F00F_IDT); + __set_fixmap(FIX_IDT, __pa(&idt_table), PAGE_KERNEL_RO); + idt_descr.address = __fix_to_virt(FIX_IDT); + __asm__ __volatile__("lidt %0" : : "m" (idt_descr)); } + +void __init trap_init_virtual_GDT(void) +{ + int cpu = smp_processor_id(); + struct Xgt_desc_struct *gdt_desc = cpu_gdt_descr + cpu; + struct Xgt_desc_struct tmp_desc = {0, 0}; + struct tss_struct * t; + + __asm__ __volatile__("sgdt %0": "=m" (tmp_desc): :"memory"); + +#ifdef CONFIG_X86_HIGH_ENTRY + if (!cpu) { + __set_fixmap(FIX_GDT_0, __pa(cpu_gdt_table), PAGE_KERNEL); + __set_fixmap(FIX_GDT_1, __pa(cpu_gdt_table) + PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_0, __pa(init_tss), PAGE_KERNEL); + __set_fixmap(FIX_TSS_1, __pa(init_tss) + 1*PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_2, __pa(init_tss) + 2*PAGE_SIZE, PAGE_KERNEL); + __set_fixmap(FIX_TSS_3, __pa(init_tss) + 3*PAGE_SIZE, PAGE_KERNEL); + } + + gdt_desc->address = __fix_to_virt(FIX_GDT_0) + sizeof(cpu_gdt_table[0]) * cpu; +#else + gdt_desc->address = (unsigned long)cpu_gdt_table[cpu]; +#endif + __asm__ __volatile__("lgdt %0": "=m" (*gdt_desc)); + +#ifdef CONFIG_X86_HIGH_ENTRY + t = (struct tss_struct *) __fix_to_virt(FIX_TSS_0) + cpu; +#else + t = init_tss + cpu; #endif + set_tss_desc(cpu, t); + cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; + load_TR_desc(); +} #define _set_gate(gate_addr,type,dpl,addr,seg) \ do { \ @@ -818,20 +949,26 @@ _set_gate(idt_table+n,14,0,addr,__KERNEL_CS); } -static void __init set_trap_gate(unsigned int n, void *addr) +void __init set_trap_gate(unsigned int n, void *addr) { _set_gate(idt_table+n,15,0,addr,__KERNEL_CS); } -static void __init set_system_gate(unsigned int n, void *addr) +void __init set_system_gate(unsigned int n, void *addr) { _set_gate(idt_table+n,15,3,addr,__KERNEL_CS); } -static void __init set_call_gate(void *a, void *addr) +void __init set_call_gate(void *a, void *addr) { _set_gate(a,12,3,addr,__KERNEL_CS); } +#ifdef CONFIG_KGDB +void set_intr_usr_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n,14,3,addr,__KERNEL_CS); +} +#endif static void __init set_task_gate(unsigned int n, unsigned int gdt_entry) { @@ -850,11 +987,16 @@ #ifdef CONFIG_X86_LOCAL_APIC init_apic_mappings(); #endif + init_entry_mappings(); set_trap_gate(0,÷_error); set_intr_gate(1,&debug); set_intr_gate(2,&nmi); +#ifndef CONFIG_KGDB set_system_gate(3,&int3); /* int3-5 can be called from all */ +#else + set_intr_usr_gate(3,&int3); /* int3-5 can be called from all */ +#endif set_system_gate(4,&overflow); set_system_gate(5,&bounds); set_trap_gate(6,&invalid_op); --- diff/arch/i386/kernel/vm86.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/i386/kernel/vm86.c 2004-02-09 10:39:50.000000000 +0000 @@ -125,7 +125,7 @@ tss = init_tss + get_cpu(); current->thread.esp0 = current->thread.saved_esp0; current->thread.sysenter_cs = __KERNEL_CS; - load_esp0(tss, ¤t->thread); + load_virtual_esp0(tss, current); current->thread.saved_esp0 = 0; put_cpu(); @@ -305,7 +305,7 @@ tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; if (cpu_has_sep) tsk->thread.sysenter_cs = 0; - load_esp0(tss, &tsk->thread); + load_virtual_esp0(tss, tsk); put_cpu(); tsk->thread.screen_bitmap = info->screen_bitmap; --- diff/arch/i386/kernel/vmlinux.lds.S 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/kernel/vmlinux.lds.S 2004-02-09 10:39:50.000000000 +0000 @@ -3,6 +3,10 @@ */ #include +#include +#include +#include +#include OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) @@ -10,7 +14,7 @@ jiffies = jiffies_64; SECTIONS { - . = 0xC0000000 + 0x100000; + . = __PAGE_OFFSET + 0x100000; /* read-only */ _text = .; /* Text and read-only data */ .text : { @@ -19,6 +23,19 @@ *(.gnu.warning) } = 0x9090 +#ifdef CONFIG_X86_4G + . = ALIGN(PAGE_SIZE_asm); + __entry_tramp_start = .; + . = FIX_ENTRY_TRAMPOLINE_0_addr; + __start___entry_text = .; + .entry.text : AT (__entry_tramp_start) { *(.entry.text) } + __entry_tramp_end = __entry_tramp_start + SIZEOF(.entry.text); + . = __entry_tramp_end; + . = ALIGN(PAGE_SIZE_asm); +#else + .entry.text : { *(.entry.text) } +#endif + _etext = .; /* End of text section */ . = ALIGN(16); /* Exception table */ @@ -34,15 +51,12 @@ CONSTRUCTORS } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __nosave_begin = .; .data_nosave : { *(.data.nosave) } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __nosave_end = .; - . = ALIGN(4096); - .data.page_aligned : { *(.data.idt) } - . = ALIGN(32); .data.cacheline_aligned : { *(.data.cacheline_aligned) } @@ -52,7 +66,7 @@ .data.init_task : { *(.data.init_task) } /* will be freed after init */ - . = ALIGN(4096); /* Init code and data */ + . = ALIGN(PAGE_SIZE_asm); /* Init code and data */ __init_begin = .; .init.text : { _sinittext = .; @@ -91,7 +105,7 @@ from .altinstructions and .eh_frame */ .exit.text : { *(.exit.text) } .exit.data : { *(.exit.data) } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; @@ -99,10 +113,22 @@ __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE_asm); __init_end = .; /* freed after init ends here */ - + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_tss : { *(.data.tss) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_default_ldt : { *(.data.default_ldt) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_idt : { *(.data.idt) } + + . = ALIGN(PAGE_SIZE_asm); + .data.page_aligned_gdt : { *(.data.gdt) } + __bss_start = .; /* BSS */ .bss : { *(.bss) } __bss_stop = .; @@ -122,4 +148,6 @@ .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } + + } --- diff/arch/i386/kernel/vsyscall-sysenter.S 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/kernel/vsyscall-sysenter.S 2004-02-09 10:39:50.000000000 +0000 @@ -7,6 +7,11 @@ .type __kernel_vsyscall,@function __kernel_vsyscall: .LSTART_vsyscall: + cmpl $192, %eax + jne 1f + int $0x80 + ret +1: push %ecx .Lpush_ecx: push %edx --- diff/arch/i386/kernel/vsyscall.lds 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/kernel/vsyscall.lds 2004-02-09 10:39:50.000000000 +0000 @@ -5,7 +5,7 @@ */ /* This must match . */ -VSYSCALL_BASE = 0xffffe000; +VSYSCALL_BASE = 0xffffd000; SECTIONS { --- diff/arch/i386/lib/Makefile 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/lib/Makefile 2004-02-09 10:39:50.000000000 +0000 @@ -9,4 +9,5 @@ lib-$(CONFIG_X86_USE_3DNOW) += mmx.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o +lib-$(CONFIG_KGDB) += kgdb_serial.o lib-$(CONFIG_DEBUG_IOVIRT) += iodebug.o --- diff/arch/i386/lib/checksum.S 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/lib/checksum.S 2004-02-09 10:39:50.000000000 +0000 @@ -280,14 +280,14 @@ .previous .align 4 -.globl csum_partial_copy_generic +.globl direct_csum_partial_copy_generic #ifndef CONFIG_X86_USE_PPRO_CHECKSUM #define ARGBASE 16 #define FP 12 -csum_partial_copy_generic: +direct_csum_partial_copy_generic: subl $4,%esp pushl %edi pushl %esi @@ -422,7 +422,7 @@ #define ARGBASE 12 -csum_partial_copy_generic: +direct_csum_partial_copy_generic: pushl %ebx pushl %edi pushl %esi --- diff/arch/i386/lib/dec_and_lock.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/lib/dec_and_lock.c 2004-02-09 10:39:50.000000000 +0000 @@ -10,6 +10,7 @@ #include #include +#ifndef ATOMIC_DEC_AND_LOCK int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) { int counter; @@ -38,3 +39,5 @@ spin_unlock(lock); return 0; } +#endif + --- diff/arch/i386/lib/getuser.S 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/lib/getuser.S 2004-02-09 10:39:50.000000000 +0000 @@ -9,6 +9,7 @@ * return value. */ #include +#include /* @@ -28,7 +29,7 @@ .globl __get_user_1 __get_user_1: GET_THREAD_INFO(%edx) - cmpl TI_ADDR_LIMIT(%edx),%eax + cmpl TI_addr_limit(%edx),%eax jae bad_get_user 1: movzbl (%eax),%edx xorl %eax,%eax @@ -40,7 +41,7 @@ addl $1,%eax jc bad_get_user GET_THREAD_INFO(%edx) - cmpl TI_ADDR_LIMIT(%edx),%eax + cmpl TI_addr_limit(%edx),%eax jae bad_get_user 2: movzwl -1(%eax),%edx xorl %eax,%eax @@ -52,7 +53,7 @@ addl $3,%eax jc bad_get_user GET_THREAD_INFO(%edx) - cmpl TI_ADDR_LIMIT(%edx),%eax + cmpl TI_addr_limit(%edx),%eax jae bad_get_user 3: movl -3(%eax),%edx xorl %eax,%eax --- diff/arch/i386/lib/mmx.c 2003-05-21 11:49:45.000000000 +0100 +++ source/arch/i386/lib/mmx.c 2004-02-09 10:39:50.000000000 +0000 @@ -121,7 +121,7 @@ return p; } -#ifdef CONFIG_MK7 +#ifdef CONFIG_CPU_ONLY_K7 /* * The K7 has streaming cache bypass load/store. The Cyrix III, K6 and --- diff/arch/i386/lib/usercopy.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/i386/lib/usercopy.c 2004-02-09 10:39:50.000000000 +0000 @@ -76,7 +76,7 @@ * and returns @count. */ long -__strncpy_from_user(char *dst, const char __user *src, long count) +__direct_strncpy_from_user(char *dst, const char __user *src, long count) { long res; __do_strncpy_from_user(dst, src, count, res); @@ -102,7 +102,7 @@ * and returns @count. */ long -strncpy_from_user(char *dst, const char __user *src, long count) +direct_strncpy_from_user(char *dst, const char __user *src, long count) { long res = -EFAULT; if (access_ok(VERIFY_READ, src, 1)) @@ -147,7 +147,7 @@ * On success, this will be zero. */ unsigned long -clear_user(void __user *to, unsigned long n) +direct_clear_user(void __user *to, unsigned long n) { might_sleep(); if (access_ok(VERIFY_WRITE, to, n)) @@ -167,7 +167,7 @@ * On success, this will be zero. */ unsigned long -__clear_user(void __user *to, unsigned long n) +__direct_clear_user(void __user *to, unsigned long n) { __do_clear_user(to, n); return n; @@ -184,7 +184,7 @@ * On exception, returns 0. * If the string is too long, returns a value greater than @n. */ -long strnlen_user(const char __user *s, long n) +long direct_strnlen_user(const char __user *s, long n) { unsigned long mask = -__addr_ok(s); unsigned long res, tmp; @@ -575,3 +575,4 @@ n = __copy_user_zeroing_intel(to, (const void *) from, n); return n; } + --- diff/arch/i386/mach-default/topology.c 2002-12-30 10:17:12.000000000 +0000 +++ source/arch/i386/mach-default/topology.c 2004-02-09 10:39:50.000000000 +0000 @@ -34,10 +34,8 @@ #ifdef CONFIG_NUMA #include #include -#include struct i386_node node_devices[MAX_NUMNODES]; -struct i386_memblk memblk_devices[MAX_NR_MEMBLKS]; static int __init topology_init(void) { @@ -47,8 +45,6 @@ arch_register_node(i); for (i = 0; i < NR_CPUS; i++) if (cpu_possible(i)) arch_register_cpu(i); - for (i = 0; i < num_online_memblks(); i++) - arch_register_memblk(i); return 0; } --- diff/arch/i386/mach-es7000/topology.c 2003-06-30 10:07:28.000000000 +0100 +++ source/arch/i386/mach-es7000/topology.c 2004-02-09 10:39:50.000000000 +0000 @@ -34,10 +34,8 @@ #ifdef CONFIG_NUMA #include #include -#include struct i386_node node_devices[MAX_NUMNODES]; -struct i386_memblk memblk_devices[MAX_NR_MEMBLKS]; static int __init topology_init(void) { @@ -47,8 +45,6 @@ arch_register_node(i); for (i = 0; i < NR_CPUS; i++) if (cpu_possible(i)) arch_register_cpu(i); - for (i = 0; i < num_online_memblks(); i++) - arch_register_memblk(i); return 0; } --- diff/arch/i386/mach-voyager/voyager_smp.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/i386/mach-voyager/voyager_smp.c 2004-02-09 10:39:50.000000000 +0000 @@ -553,7 +553,7 @@ /* For the 486, we can't use the 4Mb page table trick, so * must map a region of memory */ -#ifdef CONFIG_M486 +#ifdef CONFIG_CPU_486 int i; unsigned long *page_table_copies = (unsigned long *) __get_free_page(GFP_KERNEL); @@ -612,7 +612,7 @@ /* set the original swapper_pg_dir[0] to map 0 to 4Mb transparently * (so that the booting CPU can find start_32 */ orig_swapper_pg_dir0 = swapper_pg_dir[0]; -#ifdef CONFIG_M486 +#ifdef CONFIG_CPU_486 if(page_table_copies == NULL) panic("No free memory for 486 page tables\n"); for(i = 0; i < PAGE_SIZE/sizeof(unsigned long); i++) @@ -669,7 +669,7 @@ /* reset the page table */ swapper_pg_dir[0] = orig_swapper_pg_dir0; local_flush_tlb(); -#ifdef CONFIG_M486 +#ifdef CONFIG_CPU_486 free_page((unsigned long)page_table_copies); #endif --- diff/arch/i386/math-emu/fpu_system.h 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/math-emu/fpu_system.h 2004-02-09 10:39:50.000000000 +0000 @@ -15,6 +15,7 @@ #include #include #include +#include /* This sets the pointer FPU_info to point to the argument part of the stack frame of math_emulate() */ @@ -22,7 +23,7 @@ /* s is always from a cpu register, and the cpu does bounds checking * during register load --> no further bounds checks needed */ -#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3]) +#define LDT_DESCRIPTOR(s) (((struct desc_struct *)__kmap_atomic_vaddr(KM_LDT_PAGE0))[(s) >> 3]) #define SEG_D_SIZE(x) ((x).b & (3 << 21)) #define SEG_G_BIT(x) ((x).b & (1 << 23)) #define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1) --- diff/arch/i386/mm/fault.c 2003-12-19 09:51:11.000000000 +0000 +++ source/arch/i386/mm/fault.c 2004-02-09 10:39:50.000000000 +0000 @@ -27,6 +27,7 @@ #include #include #include +#include extern void die(const char *,struct pt_regs *,long); @@ -104,8 +105,17 @@ if (seg & (1<<2)) { /* Must lock the LDT while reading it. */ down(¤t->mm->context.sem); +#if 1 + /* horrible hack for 4/4 disabled kernels. + I'm not quite sure what the TLB flush is good for, + it's mindlessly copied from the read_ldt code */ + __flush_tlb_global(); + desc = kmap(current->mm->context.ldt_pages[(seg&~7)/PAGE_SIZE]); + desc = (void *)desc + ((seg & ~7) % PAGE_SIZE); +#else desc = current->mm->context.ldt; desc = (void *)desc + (seg & ~7); +#endif } else { /* Must disable preemption while reading the GDT. */ desc = (u32 *)&cpu_gdt_table[get_cpu()]; @@ -118,6 +128,9 @@ (desc[1] & 0xff000000); if (seg & (1<<2)) { +#if 1 + kunmap((void *)((unsigned long)desc & PAGE_MASK)); +#endif up(¤t->mm->context.sem); } else put_cpu(); @@ -243,6 +256,19 @@ * (error_code & 4) == 0, and that the fault was not a * protection error (error_code & 1) == 0. */ +#ifdef CONFIG_X86_4G + /* + * On 4/4 all kernels faults are either bugs, vmalloc or prefetch + */ + if (unlikely((regs->xcs & 3) == 0)) { + if (error_code & 3) + goto bad_area_nosemaphore; + + /* If it's vm86 fall through */ + if (!(regs->eflags & VM_MASK)) + goto vmalloc_fault; + } +#else if (unlikely(address >= TASK_SIZE)) { if (!(error_code & 5)) goto vmalloc_fault; @@ -252,6 +278,7 @@ */ goto bad_area_nosemaphore; } +#endif mm = tsk->mm; @@ -403,6 +430,12 @@ * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. */ +#ifdef CONFIG_KGDB + if (!user_mode(regs)){ + kgdb_handle_exception(14,SIGBUS, error_code, regs); + return; + } +#endif bust_spinlocks(1); --- diff/arch/i386/mm/init.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/i386/mm/init.c 2004-02-09 10:39:50.000000000 +0000 @@ -40,125 +40,13 @@ #include #include #include +#include DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); unsigned long highstart_pfn, highend_pfn; static int do_test_wp_bit(void); -/* - * Creates a middle page table and puts a pointer to it in the - * given global directory entry. This only returns the gd entry - * in non-PAE compilation mode, since the middle layer is folded. - */ -static pmd_t * __init one_md_table_init(pgd_t *pgd) -{ - pmd_t *pmd_table; - -#ifdef CONFIG_X86_PAE - pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); - if (pmd_table != pmd_offset(pgd, 0)) - BUG(); -#else - pmd_table = pmd_offset(pgd, 0); -#endif - - return pmd_table; -} - -/* - * Create a page table and place a pointer to it in a middle page - * directory entry. - */ -static pte_t * __init one_page_table_init(pmd_t *pmd) -{ - if (pmd_none(*pmd)) { - pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); - if (page_table != pte_offset_kernel(pmd, 0)) - BUG(); - - return page_table; - } - - return pte_offset_kernel(pmd, 0); -} - -/* - * This function initializes a certain range of kernel virtual memory - * with new bootmem page tables, everywhere page tables are missing in - * the given range. - */ - -/* - * NOTE: The pagetables are allocated contiguous on the physical space - * so we can cache the place of the first one and move around without - * checking the pgd every time. - */ -static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base) -{ - pgd_t *pgd; - pmd_t *pmd; - int pgd_idx, pmd_idx; - unsigned long vaddr; - - vaddr = start; - pgd_idx = pgd_index(vaddr); - pmd_idx = pmd_index(vaddr); - pgd = pgd_base + pgd_idx; - - for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { - if (pgd_none(*pgd)) - one_md_table_init(pgd); - - pmd = pmd_offset(pgd, vaddr); - for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) { - if (pmd_none(*pmd)) - one_page_table_init(pmd); - - vaddr += PMD_SIZE; - } - pmd_idx = 0; - } -} - -/* - * This maps the physical memory to kernel virtual address space, a total - * of max_low_pfn pages, by creating page tables starting from address - * PAGE_OFFSET. - */ -static void __init kernel_physical_mapping_init(pgd_t *pgd_base) -{ - unsigned long pfn; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - int pgd_idx, pmd_idx, pte_ofs; - - pgd_idx = pgd_index(PAGE_OFFSET); - pgd = pgd_base + pgd_idx; - pfn = 0; - - for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) { - pmd = one_md_table_init(pgd); - if (pfn >= max_low_pfn) - continue; - for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) { - /* Map with big pages if possible, otherwise create normal page tables. */ - if (cpu_has_pse) { - set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); - pfn += PTRS_PER_PTE; - } else { - pte = one_page_table_init(pmd); - - for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) - set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); - } - } - } -} - static inline int page_kills_ppro(unsigned long pagenr) { if (pagenr >= 0x70000 && pagenr <= 0x7003F) @@ -206,11 +94,8 @@ return 0; } -#ifdef CONFIG_HIGHMEM pte_t *kmap_pte; -pgprot_t kmap_prot; -EXPORT_SYMBOL(kmap_prot); EXPORT_SYMBOL(kmap_pte); #define kmap_get_fixmap_pte(vaddr) \ @@ -218,29 +103,7 @@ void __init kmap_init(void) { - unsigned long kmap_vstart; - - /* cache the first kmap pte */ - kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); - kmap_pte = kmap_get_fixmap_pte(kmap_vstart); - - kmap_prot = PAGE_KERNEL; -} - -void __init permanent_kmaps_init(pgd_t *pgd_base) -{ - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - unsigned long vaddr; - - vaddr = PKMAP_BASE; - page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); - - pgd = swapper_pg_dir + pgd_index(vaddr); - pmd = pmd_offset(pgd, vaddr); - pte = pte_offset_kernel(pmd, vaddr); - pkmap_page_table = pte; + kmap_pte = kmap_get_fixmap_pte(__fix_to_virt(FIX_KMAP_BEGIN)); } void __init one_highpage_init(struct page *page, int pfn, int bad_ppro) @@ -255,6 +118,8 @@ SetPageReserved(page); } +#ifdef CONFIG_HIGHMEM + #ifndef CONFIG_DISCONTIGMEM void __init set_highmem_pages_init(int bad_ppro) { @@ -266,12 +131,9 @@ #else extern void set_highmem_pages_init(int); #endif /* !CONFIG_DISCONTIGMEM */ - #else -#define kmap_init() do { } while (0) -#define permanent_kmaps_init(pgd_base) do { } while (0) -#define set_highmem_pages_init(bad_ppro) do { } while (0) -#endif /* CONFIG_HIGHMEM */ +# define set_highmem_pages_init(bad_ppro) do { } while (0) +#endif unsigned long __PAGE_KERNEL = _PAGE_KERNEL; @@ -281,30 +143,125 @@ extern void __init remap_numa_kva(void); #endif -static void __init pagetable_init (void) +static __init void prepare_pagetables(pgd_t *pgd_base, unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + pgd = pgd_base + pgd_index(address); + pmd = pmd_offset(pgd, address); + if (!pmd_present(*pmd)) { + pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); + } +} + +static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t *pgd_base) +{ + unsigned long vaddr; + + for (vaddr = start; vaddr != end; vaddr += PAGE_SIZE) + prepare_pagetables(pgd_base, vaddr); +} + +void setup_identity_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end) { unsigned long vaddr; - pgd_t *pgd_base = swapper_pg_dir; + pgd_t *pgd; + int i, j, k; + pmd_t *pmd; + pte_t *pte, *pte_base; + + pgd = pgd_base; + + for (i = 0; i < PTRS_PER_PGD; pgd++, i++) { + vaddr = i*PGDIR_SIZE; + if (end && (vaddr >= end)) + break; + pmd = pmd_offset(pgd, 0); + for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + if (cpu_has_pse) { + unsigned long __pe; + set_in_cr4(X86_CR4_PSE); + boot_cpu_data.wp_works_ok = 1; + __pe = _KERNPG_TABLE + _PAGE_PSE + vaddr - start; + /* Make it "global" too if supported */ + if (cpu_has_pge) { + set_in_cr4(X86_CR4_PGE); +#if !defined(CONFIG_X86_SWITCH_PAGETABLES) + __pe += _PAGE_GLOBAL; + __PAGE_KERNEL |= _PAGE_GLOBAL; +#endif + } + set_pmd(pmd, __pmd(__pe)); + continue; + } + if (!pmd_present(*pmd)) + pte_base = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + else + pte_base = (pte_t *) page_address(pmd_page(*pmd)); + pte = pte_base; + for (k = 0; k < PTRS_PER_PTE; pte++, k++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + *pte = mk_pte_phys(vaddr-start, PAGE_KERNEL); + } + set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base))); + } + } +} + +static void __init pagetable_init (void) +{ + unsigned long vaddr, end; + pgd_t *pgd_base; #ifdef CONFIG_X86_PAE int i; - /* Init entries of the first-level page table to the zero page */ - for (i = 0; i < PTRS_PER_PGD; i++) - set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT)); #endif - /* Enable PSE if available */ - if (cpu_has_pse) { - set_in_cr4(X86_CR4_PSE); - } + /* + * This can be zero as well - no problem, in that case we exit + * the loops anyway due to the PTRS_PER_* conditions. + */ + end = (unsigned long)__va(max_low_pfn*PAGE_SIZE); - /* Enable PGE if available */ - if (cpu_has_pge) { - set_in_cr4(X86_CR4_PGE); - __PAGE_KERNEL |= _PAGE_GLOBAL; + pgd_base = swapper_pg_dir; +#ifdef CONFIG_X86_PAE + /* + * It causes too many problems if there's no proper pmd set up + * for all 4 entries of the PGD - so we allocate all of them. + * PAE systems will not miss this extra 4-8K anyway ... + */ + for (i = 0; i < PTRS_PER_PGD; i++) { + pmd_t *pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pgd(pgd_base + i, __pgd(__pa(pmd) + 0x1)); } +#endif + /* + * Set up lowmem-sized identity mappings at PAGE_OFFSET: + */ + setup_identity_mappings(pgd_base, PAGE_OFFSET, end); - kernel_physical_mapping_init(pgd_base); + /* + * Add flat-mode identity-mappings - SMP needs it when + * starting up on an AP from real-mode. (In the non-PAE + * case we already have these mappings through head.S.) + * All user-space mappings are explicitly cleared after + * SMP startup. + */ +#if CONFIG_SMP && CONFIG_X86_PAE + setup_identity_mappings(pgd_base, 0, 16*1024*1024); +#endif remap_numa_kva(); /* @@ -312,38 +269,64 @@ * created - mappings will be set by set_fixmap(): */ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; - page_table_range_init(vaddr, 0, pgd_base); + fixrange_init(vaddr, 0, pgd_base); - permanent_kmaps_init(pgd_base); +#if CONFIG_HIGHMEM + { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; -#ifdef CONFIG_X86_PAE - /* - * Add low memory identity-mappings - SMP needs it when - * starting up on an AP from real-mode. In the non-PAE - * case we already have these mappings through head.S. - * All user-space mappings are explicitly cleared after - * SMP startup. - */ - pgd_base[0] = pgd_base[USER_PTRS_PER_PGD]; + /* + * Permanent kmaps: + */ + vaddr = PKMAP_BASE; + fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); + + pgd = swapper_pg_dir + pgd_index(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset_kernel(pmd, vaddr); + pkmap_page_table = pte; + } #endif } -void zap_low_mappings (void) +/* + * Clear kernel pagetables in a PMD_SIZE-aligned range. + */ +static void clear_mappings(pgd_t *pgd_base, unsigned long start, unsigned long end) { - int i; + unsigned long vaddr; + pgd_t *pgd; + pmd_t *pmd; + int i, j; + + pgd = pgd_base; + + for (i = 0; i < PTRS_PER_PGD; pgd++, i++) { + vaddr = i*PGDIR_SIZE; + if (end && (vaddr >= end)) + break; + pmd = pmd_offset(pgd, 0); + for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (end && (vaddr >= end)) + break; + if (vaddr < start) + continue; + pmd_clear(pmd); + } + } + flush_tlb_all(); +} + +void zap_low_mappings(void) +{ + printk("zapping low mappings.\n"); /* * Zap initial low-memory mappings. - * - * Note that "pgd_clear()" doesn't do it for - * us, because pgd_clear() is a no-op on i386. */ - for (i = 0; i < USER_PTRS_PER_PGD; i++) -#ifdef CONFIG_X86_PAE - set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page))); -#else - set_pgd(swapper_pg_dir+i, __pgd(0)); -#endif - flush_tlb_all(); + clear_mappings(swapper_pg_dir, 0, 16*1024*1024); } #ifndef CONFIG_DISCONTIGMEM @@ -393,7 +376,15 @@ set_in_cr4(X86_CR4_PAE); #endif __flush_tlb_all(); - + /* + * Subtle. SMP is doing it's boot stuff late (because it has to + * fork idle threads) - but it also needs low mappings for the + * protected-mode entry to work. We zap these entries only after + * the WP-bit has been tested. + */ +#ifndef CONFIG_SMP + zap_low_mappings(); +#endif kmap_init(); zone_sizes_init(); } @@ -515,22 +506,18 @@ if (boot_cpu_data.wp_works_ok < 0) test_wp_bit(); - /* - * Subtle. SMP is doing it's boot stuff late (because it has to - * fork idle threads) - but it also needs low mappings for the - * protected-mode entry to work. We zap these entries only after - * the WP-bit has been tested. - */ -#ifndef CONFIG_SMP - zap_low_mappings(); -#endif + entry_trampoline_setup(); + default_ldt_page = virt_to_page(default_ldt); + load_LDT(&init_mm.context); } -kmem_cache_t *pgd_cache; -kmem_cache_t *pmd_cache; +kmem_cache_t *pgd_cache, *pmd_cache, *kpmd_cache; void __init pgtable_cache_init(void) { + void (*ctor)(void *, kmem_cache_t *, unsigned long); + void (*dtor)(void *, kmem_cache_t *, unsigned long); + if (PTRS_PER_PMD > 1) { pmd_cache = kmem_cache_create("pmd", PTRS_PER_PMD*sizeof(pmd_t), @@ -540,13 +527,36 @@ NULL); if (!pmd_cache) panic("pgtable_cache_init(): cannot create pmd cache"); + + if (TASK_SIZE > PAGE_OFFSET) { + kpmd_cache = kmem_cache_create("kpmd", + PTRS_PER_PMD*sizeof(pmd_t), + 0, + SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, + kpmd_ctor, + NULL); + if (!kpmd_cache) + panic("pgtable_cache_init(): " + "cannot create kpmd cache"); + } } + + if (PTRS_PER_PMD == 1 || TASK_SIZE <= PAGE_OFFSET) + ctor = pgd_ctor; + else + ctor = NULL; + + if (PTRS_PER_PMD == 1 && TASK_SIZE <= PAGE_OFFSET) + dtor = pgd_dtor; + else + dtor = NULL; + pgd_cache = kmem_cache_create("pgd", PTRS_PER_PGD*sizeof(pgd_t), 0, SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN, - pgd_ctor, - PTRS_PER_PMD == 1 ? pgd_dtor : NULL); + ctor, + dtor); if (!pgd_cache) panic("pgtable_cache_init(): Cannot create pgd cache"); } --- diff/arch/i386/mm/pgtable.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/i386/mm/pgtable.c 2004-02-09 10:39:50.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include void show_mem(void) { @@ -157,11 +158,20 @@ memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t)); } +void kpmd_ctor(void *__pmd, kmem_cache_t *cache, unsigned long flags) +{ + pmd_t *kpmd, *pmd; + kpmd = pmd_offset(&swapper_pg_dir[PTRS_PER_PGD-1], + (PTRS_PER_PMD - NR_SHARED_PMDS)*PMD_SIZE); + pmd = (pmd_t *)__pmd + (PTRS_PER_PMD - NR_SHARED_PMDS); + + memset(__pmd, 0, (PTRS_PER_PMD - NR_SHARED_PMDS)*sizeof(pmd_t)); + memcpy(pmd, kpmd, NR_SHARED_PMDS*sizeof(pmd_t)); +} + /* - * List of all pgd's needed for non-PAE so it can invalidate entries - * in both cached and uncached pgd's; not needed for PAE since the - * kernel pmd is shared. If PAE were not to share the pmd a similar - * tactic would be needed. This is essentially codepath-based locking + * List of all pgd's needed so it can invalidate entries in both cached + * and uncached pgd's. This is essentially codepath-based locking * against pageattr.c; it is the unique case in which a valid change * of kernel pagetables can't be lazily synchronized by vmalloc faults. * vmalloc faults work because attached pagetables are never freed. @@ -170,30 +180,60 @@ * could be used. The locking scheme was chosen on the basis of * manfred's recommendations and having no core impact whatsoever. * -- wli + * + * The entire issue goes away when XKVA is configured. */ spinlock_t pgd_lock = SPIN_LOCK_UNLOCKED; LIST_HEAD(pgd_list); -void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused) +/* + * This is not that hard to figure out. + * (a) PTRS_PER_PMD == 1 means non-PAE. + * (b) PTRS_PER_PMD > 1 means PAE. + * (c) TASK_SIZE > PAGE_OFFSET means XKVA. + * (d) TASK_SIZE <= PAGE_OFFSET means non-XKVA. + * + * Do *NOT* back out the preconstruction like the patch I'm cleaning + * up after this very instant did, or at all, for that matter. + * This is never called when PTRS_PER_PMD > 1 && TASK_SIZE > PAGE_OFFSET. + * -- wli + */ +void pgd_ctor(void *__pgd, kmem_cache_t *cache, unsigned long unused) { + pgd_t *pgd = (pgd_t *)__pgd; unsigned long flags; - if (PTRS_PER_PMD == 1) - spin_lock_irqsave(&pgd_lock, flags); + if (PTRS_PER_PMD == 1) { + if (TASK_SIZE <= PAGE_OFFSET) + spin_lock_irqsave(&pgd_lock, flags); + else + memcpy(&pgd[PTRS_PER_PGD - NR_SHARED_PMDS], + &swapper_pg_dir[PTRS_PER_PGD - NR_SHARED_PMDS], + NR_SHARED_PMDS * sizeof(pgd_t)); + } - memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD, - swapper_pg_dir + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + if (TASK_SIZE <= PAGE_OFFSET) + memcpy(pgd + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); if (PTRS_PER_PMD > 1) return; - list_add(&virt_to_page(pgd)->lru, &pgd_list); - spin_unlock_irqrestore(&pgd_lock, flags); - memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); + if (TASK_SIZE > PAGE_OFFSET) + memset(pgd, 0, (PTRS_PER_PGD - NR_SHARED_PMDS)*sizeof(pgd_t)); + else { + list_add(&virt_to_page(pgd)->lru, &pgd_list); + spin_unlock_irqrestore(&pgd_lock, flags); + memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); + } } -/* never called when PTRS_PER_PMD > 1 */ +/* + * Never called when PTRS_PER_PMD > 1 || TASK_SIZE > PAGE_OFFSET + * for with PAE we would list_del() multiple times, and for non-PAE + * with XKVA all the AGP pgd shootdown code is unnecessary. + */ void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused) { unsigned long flags; /* can be called from interrupt context */ @@ -203,6 +243,12 @@ spin_unlock_irqrestore(&pgd_lock, flags); } +/* + * See the comments above pgd_ctor() wrt. preconstruction. + * Do *NOT* memcpy() here. If you do, you back out important + * anti- cache pollution code. + * + */ pgd_t *pgd_alloc(struct mm_struct *mm) { int i; @@ -211,15 +257,33 @@ if (PTRS_PER_PMD == 1 || !pgd) return pgd; + /* + * In the 4G userspace case alias the top 16 MB virtual + * memory range into the user mappings as well (these + * include the trampoline and CPU data structures). + */ for (i = 0; i < USER_PTRS_PER_PGD; ++i) { - pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL); + kmem_cache_t *cache; + pmd_t *pmd; + + if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1) + cache = kpmd_cache; + else + cache = pmd_cache; + + pmd = kmem_cache_alloc(cache, GFP_KERNEL); if (!pmd) goto out_oom; set_pgd(&pgd[i], __pgd(1 + __pa((u64)((u32)pmd)))); } - return pgd; + return pgd; out_oom: + /* + * we don't have to handle the kpmd_cache here, since it's the + * last allocation, and has either nothing to free or when it + * succeeds the whole operation succeeds. + */ for (i--; i >= 0; i--) kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1)); kmem_cache_free(pgd_cache, pgd); @@ -230,10 +294,29 @@ { int i; - /* in the PAE case user pgd entries are overwritten before usage */ - if (PTRS_PER_PMD > 1) - for (i = 0; i < USER_PTRS_PER_PGD; ++i) - kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1)); /* in the non-PAE case, clear_page_tables() clears user pgd entries */ + if (PTRS_PER_PMD == 1) + goto out_free; + + /* in the PAE case user pgd entries are overwritten before usage */ + for (i = 0; i < USER_PTRS_PER_PGD; ++i) { + kmem_cache_t *cache; + pmd_t *pmd = __va(pgd_val(pgd[i]) - 1); + + /* + * only userspace pmd's are cleared for us + * by mm/memory.c; it's a slab cache invariant + * that we must separate the kernel pmd slab + * all times, else we'll have bad pmd's. + */ + if (TASK_SIZE > PAGE_OFFSET && i == USER_PTRS_PER_PGD - 1) + cache = kpmd_cache; + else + cache = pmd_cache; + + kmem_cache_free(cache, pmd); + } +out_free: kmem_cache_free(pgd_cache, pgd); } + --- diff/arch/i386/oprofile/op_model_p4.c 2003-08-26 10:00:51.000000000 +0100 +++ source/arch/i386/oprofile/op_model_p4.c 2004-02-09 10:39:50.000000000 +0000 @@ -382,11 +382,8 @@ static unsigned int get_stagger(void) { #ifdef CONFIG_SMP - int cpu; - if (smp_num_siblings > 1) { - cpu = smp_processor_id(); - return (cpu_sibling_map[cpu] > cpu) ? 0 : 1; - } + int cpu = smp_processor_id(); + return (cpu != first_cpu(cpu_sibling_map[cpu])); #endif return 0; } --- diff/arch/i386/pci/Makefile 2003-07-08 09:55:17.000000000 +0100 +++ source/arch/i386/pci/Makefile 2004-02-09 10:39:50.000000000 +0000 @@ -1,6 +1,7 @@ obj-y := i386.o obj-$(CONFIG_PCI_BIOS) += pcbios.o +obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o obj-$(CONFIG_PCI_DIRECT) += direct.o pci-y := fixup.o --- diff/arch/i386/pci/common.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/i386/pci/common.c 2004-02-09 10:39:50.000000000 +0000 @@ -20,7 +20,8 @@ extern void pcibios_sort(void); #endif -unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2; +unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | + PCI_PROBE_MMCONF; int pcibios_last_bus = -1; struct pci_bus *pci_root_bus = NULL; @@ -198,6 +199,12 @@ return NULL; } #endif +#ifdef CONFIG_PCI_MMCONFIG + else if (!strcmp(str, "nommconf")) { + pci_probe &= ~PCI_PROBE_MMCONF; + return NULL; + } +#endif else if (!strcmp(str, "noacpi")) { acpi_noirq_set(); return NULL; --- diff/arch/i386/pci/irq.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/i386/pci/irq.c 2004-02-09 10:39:50.000000000 +0000 @@ -943,12 +943,50 @@ { u8 pin; extern int interrupt_line_quirk; + struct pci_dev *temp_dev; + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) { char *msg; - if (io_apic_assign_pci_irqs) - msg = " Probably buggy MP table."; - else if (pci_probe & PCI_BIOS_IRQ_SCAN) + msg = ""; + if (io_apic_assign_pci_irqs) { + int irq; + + if (pin) { + pin--; /* interrupt pins are numbered starting from 1 */ + irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); + /* + * Busses behind bridges are typically not listed in the MP-table. + * In this case we have to look up the IRQ based on the parent bus, + * parent slot, and pin number. The SMP code detects such bridged + * busses itself so we should get into this branch reliably. + */ + temp_dev = dev; + while (irq < 0 && dev->bus->parent) { /* go back to the bridge */ + struct pci_dev * bridge = dev->bus->self; + + pin = (pin + PCI_SLOT(dev->devfn)) % 4; + irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, + PCI_SLOT(bridge->devfn), pin); + if (irq >= 0) + printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", + bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq); + dev = bridge; + } + dev = temp_dev; + if (irq >= 0) { +#ifdef CONFIG_PCI_USE_VECTOR + if (!platform_legacy_irq(irq)) + irq = IO_APIC_VECTOR(irq); +#endif + printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n", + dev->bus->number, PCI_SLOT(dev->devfn), pin, irq); + dev->irq = irq; + return 0; + } else + msg = " Probably buggy MP table."; + } + } else if (pci_probe & PCI_BIOS_IRQ_SCAN) msg = ""; else msg = " Please try using pci=biosirq."; --- diff/arch/i386/pci/pci.h 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/i386/pci/pci.h 2004-02-09 10:39:50.000000000 +0000 @@ -15,6 +15,9 @@ #define PCI_PROBE_BIOS 0x0001 #define PCI_PROBE_CONF1 0x0002 #define PCI_PROBE_CONF2 0x0004 +#define PCI_PROBE_MMCONF 0x0008 +#define PCI_PROBE_MASK 0x000f + #define PCI_NO_SORT 0x0100 #define PCI_BIOS_SORT 0x0200 #define PCI_NO_CHECKS 0x0400 --- diff/arch/ia64/Kconfig 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/Kconfig 2004-02-09 10:39:51.000000000 +0000 @@ -662,6 +662,13 @@ Say Y here only if you plan to use gdb to debug the kernel. If you don't debug the kernel, you can say N. +config LOCKMETER + bool "Kernel lock metering" + depends on SMP + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + endmenu source "security/Kconfig" --- diff/arch/ia64/hp/sim/simeth.c 2003-08-20 14:16:08.000000000 +0100 +++ source/arch/ia64/hp/sim/simeth.c 2004-02-09 10:39:50.000000000 +0000 @@ -224,7 +224,7 @@ err = register_netdev(dev); if (err) { - kfree(dev); + free_netdev(dev); return err; } --- diff/arch/ia64/ia32/sys_ia32.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/ia32/sys_ia32.c 2004-02-09 10:39:51.000000000 +0000 @@ -2413,44 +2413,86 @@ return sys_lseek(fd, offset, whence); } -extern asmlinkage long sys_getgroups (int gidsetsize, gid_t *grouplist); +static int +groups16_to_user(short *grouplist, struct group_info *group_info) +{ + int i; + short group; + + for (i = 0; i < group_info->ngroups; i++) { + group = (short)GROUP_AT(group_info, i); + if (put_user(group, grouplist+i)) + return -EFAULT; + } + + return 0; +} + +static int +groups16_from_user(struct group_info *group_info, short *grouplist) +{ + int i; + short group; + + for (i = 0; i < group_info->ngroups; i++) { + if (get_user(group, grouplist+i)) + return -EFAULT; + GROUP_AT(group_info, i) = (gid_t)group; + } + + return 0; +} asmlinkage long sys32_getgroups16 (int gidsetsize, short *grouplist) { - mm_segment_t old_fs = get_fs(); - gid_t gl[NGROUPS]; - int ret, i; + int i; - set_fs(KERNEL_DS); - ret = sys_getgroups(gidsetsize, gl); - set_fs(old_fs); + if (gidsetsize < 0) + return -EINVAL; - if (gidsetsize && ret > 0 && ret <= NGROUPS) - for (i = 0; i < ret; i++, grouplist++) - if (put_user(gl[i], grouplist)) - return -EFAULT; - return ret; + get_group_info(current->group_info); + i = current->group_info->ngroups; + if (gidsetsize) { + if (i > gidsetsize) { + i = -EINVAL; + goto out; + } + if (groups16_to_user(grouplist, current->group_info)) { + i = -EFAULT; + goto out; + } + } +out: + put_group_info(current->group_info); + return i; } -extern asmlinkage long sys_setgroups (int gidsetsize, gid_t *grouplist); - asmlinkage long sys32_setgroups16 (int gidsetsize, short *grouplist) { - mm_segment_t old_fs = get_fs(); - gid_t gl[NGROUPS]; - int ret, i; + struct group_info *group_info; + int retval; - if ((unsigned) gidsetsize > NGROUPS) + if (!capable(CAP_SETGID)) + return -EPERM; + if ((unsigned)gidsetsize > NGROUPS_MAX) return -EINVAL; - for (i = 0; i < gidsetsize; i++, grouplist++) - if (get_user(gl[i], grouplist)) - return -EFAULT; - set_fs(KERNEL_DS); - ret = sys_setgroups(gidsetsize, gl); - set_fs(old_fs); - return ret; + + group_info = groups_alloc(gidsetsize); + if (!group_info) + return -ENOMEM; + retval = groups16_from_user(group_info, grouplist); + if (retval) { + put_group_info(group_info); + return retval; + } + + retval = set_current_groups(group_info); + if (retval) + put_group_info(group_info); + + return retval; } asmlinkage long --- diff/arch/ia64/kernel/acpi.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/kernel/acpi.c 2004-02-09 10:39:51.000000000 +0000 @@ -191,8 +191,6 @@ if (!lsapic->flags.enabled) printk(" disabled"); - else if (available_cpus >= NR_CPUS) - printk(" ignored (increase NR_CPUS)"); else { printk(" enabled"); #ifdef CONFIG_SMP @@ -395,12 +393,6 @@ size = ma->length_hi; size = (size << 32) | ma->length_lo; - if (num_memblks >= NR_MEMBLKS) { - printk(KERN_ERR "Too many mem chunks in SRAT. Ignoring %ld MBytes at %lx\n", - size/(1024*1024), paddr); - return; - } - /* Ignore disabled entries */ if (!ma->flags.enabled) return; @@ -409,7 +401,7 @@ pxm_bit_set(pxm); /* Insertion sort based on base address */ - pend = &node_memblk[num_memblks]; + pend = &node_memblk[num_node_memblks]; for (p = &node_memblk[0]; p < pend; p++) { if (paddr < p->start_paddr) break; @@ -421,7 +413,7 @@ p->start_paddr = paddr; p->size = size; p->nid = pxm; - num_memblks++; + num_node_memblks++; } void __init @@ -448,7 +440,7 @@ } /* set logical node id in memory chunk structure */ - for (i = 0; i < num_memblks; i++) + for (i = 0; i < num_node_memblks; i++) node_memblk[i].nid = pxm_to_nid_map[node_memblk[i].nid]; /* assign memory bank numbers for each chunk on each node */ @@ -456,7 +448,7 @@ int bank; bank = 0; - for (j = 0; j < num_memblks; j++) + for (j = 0; j < num_node_memblks; j++) if (node_memblk[j].nid == i) node_memblk[j].bank = bank++; } @@ -466,7 +458,7 @@ node_cpuid[i].nid = pxm_to_nid_map[node_cpuid[i].nid]; printk(KERN_INFO "Number of logical nodes in system = %d\n", numnodes); - printk(KERN_INFO "Number of memory chunks in system = %d\n", num_memblks); + printk(KERN_INFO "Number of memory chunks in system = %d\n", num_node_memblks); if (!slit_table) return; memset(numa_slit, -1, sizeof(numa_slit)); @@ -552,29 +544,29 @@ /* Local APIC */ - if (acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr) < 0) + if (acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0) < 0) printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); - if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic) < 1) + if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic, NR_CPUS) < 1) printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries\n"); - if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi) < 0) + if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0) < 0) printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); /* I/O APIC */ - if (acpi_table_parse_madt(ACPI_MADT_IOSAPIC, acpi_parse_iosapic) < 1) + if (acpi_table_parse_madt(ACPI_MADT_IOSAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1) printk(KERN_ERR PREFIX "Error parsing MADT - no IOSAPIC entries\n"); /* System-Level Interrupt Routing */ - if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src) < 0) + if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src, ACPI_MAX_PLATFORM_INTERRUPTS) < 0) printk(KERN_ERR PREFIX "Error parsing platform interrupt source entry\n"); - if (acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr) < 0) + if (acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, 0) < 0) printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); - if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src) < 0) + if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, 0) < 0) printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); skip_madt: --- diff/arch/ia64/kernel/iosapic.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/ia64/kernel/iosapic.c 2004-02-09 10:39:51.000000000 +0000 @@ -114,7 +114,7 @@ char *addr; /* base address of IOSAPIC */ unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ unsigned short num_rte; /* number of RTE in this IOSAPIC */ -} iosapic_lists[256]; +} iosapic_lists[NR_IOSAPICS]; static int num_iosapic; --- diff/arch/ia64/kernel/unwind.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/kernel/unwind.c 2004-02-09 10:39:51.000000000 +0000 @@ -650,7 +650,7 @@ /* Unwind decoder routines */ -static enum unw_register_index __attribute__((const)) +static enum unw_register_index __attribute_const__ decode_abreg (unsigned char abreg, int memory) { switch (abreg) { --- diff/arch/ia64/lib/dec_and_lock.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/ia64/lib/dec_and_lock.c 2004-02-09 10:39:51.000000000 +0000 @@ -13,6 +13,7 @@ #include #include +#ifndef CONFIG_LOCKMETER /* * Decrement REFCOUNT and if the count reaches zero, acquire the spinlock. Both of these * operations have to be done atomically, so that the count doesn't drop to zero without @@ -40,3 +41,4 @@ } EXPORT_SYMBOL(atomic_dec_and_lock); +#endif --- diff/arch/ia64/mm/discontig.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/ia64/mm/discontig.c 2004-02-09 10:39:51.000000000 +0000 @@ -419,14 +419,14 @@ func = arg; - if (!num_memblks) { - /* No SRAT table, to assume one node (node 0) */ + if (!num_node_memblks) { + /* No SRAT table, so assume one node (node 0) */ if (start < end) (*func)(start, len, 0); return; } - for (i = 0; i < num_memblks; i++) { + for (i = 0; i < num_node_memblks; i++) { rs = max(start, node_memblk[i].start_paddr); re = min(end, node_memblk[i].start_paddr + node_memblk[i].size); --- diff/arch/ia64/mm/numa.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/mm/numa.c 2004-02-09 10:39:51.000000000 +0000 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -21,7 +20,6 @@ #include #include -static struct memblk *sysfs_memblks; static struct node *sysfs_nodes; static struct cpu *sysfs_cpus; @@ -29,8 +27,8 @@ * The following structures are usually initialized by ACPI or * similar mechanisms and describe the NUMA characteristics of the machine. */ -int num_memblks; -struct node_memblk_s node_memblk[NR_MEMBLKS]; +int num_node_memblks; +struct node_memblk_s node_memblk[NR_NODE_MEMBLKS]; struct node_cpuid_s node_cpuid[NR_CPUS]; /* * This is a matrix with "distances" between nodes, they should be @@ -44,12 +42,12 @@ { int i; - for (i = 0; i < num_memblks; i++) + for (i = 0; i < num_node_memblks; i++) if (paddr >= node_memblk[i].start_paddr && paddr < node_memblk[i].start_paddr + node_memblk[i].size) break; - return (i < num_memblks) ? node_memblk[i].nid : (num_memblks ? -1 : 0); + return (i < num_node_memblks) ? node_memblk[i].nid : (num_node_memblks ? -1 : 0); } static int __init topology_init(void) @@ -63,18 +61,8 @@ } memset(sysfs_nodes, 0, sizeof(struct node) * numnodes); - sysfs_memblks = kmalloc(sizeof(struct memblk) * num_memblks, - GFP_KERNEL); - if (!sysfs_memblks) { - kfree(sysfs_nodes); - err = -ENOMEM; - goto out; - } - memset(sysfs_memblks, 0, sizeof(struct memblk) * num_memblks); - sysfs_cpus = kmalloc(sizeof(struct cpu) * NR_CPUS, GFP_KERNEL); if (!sysfs_cpus) { - kfree(sysfs_memblks); kfree(sysfs_nodes); err = -ENOMEM; goto out; @@ -85,11 +73,6 @@ if ((err = register_node(&sysfs_nodes[i], i, 0))) goto out; - for (i = 0; i < num_memblks; i++) - if ((err = register_memblk(&sysfs_memblks[i], i, - &sysfs_nodes[memblk_to_node(i)]))) - goto out; - for (i = 0; i < NR_CPUS; i++) if (cpu_online(i)) if((err = register_cpu(&sysfs_cpus[i], i, --- diff/arch/ia64/sn/io/hwgfs/hcl.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/hwgfs/hcl.c 2004-02-09 10:39:51.000000000 +0000 @@ -645,7 +645,7 @@ void -hwgraph_debug(char *file, char * function, int line, vertex_hdl_t vhdl1, vertex_hdl_t vhdl2, char *format, ...) +hwgraph_debug(char *file, const char * function, int line, vertex_hdl_t vhdl1, vertex_hdl_t vhdl2, char *format, ...) { int pos; --- diff/arch/ia64/sn/io/hwgfs/hcl_util.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/hwgfs/hcl_util.c 2004-02-09 10:39:51.000000000 +0000 @@ -151,7 +151,7 @@ (void)hwgraph_edge_add( hwgraph_all_cnodes, vhdl, cnodeid_buffer); - HWGRAPH_DEBUG((__FILE__, __FUNCTION__, __LINE__, hwgraph_all_cnodes, NULL, "Creating path vhdl1\n")); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, hwgraph_all_cnodes, NULL, "Creating path vhdl1\n"); } } --- diff/arch/ia64/sn/io/io.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/io.c 2004-02-09 10:39:51.000000000 +0000 @@ -6,9 +6,9 @@ * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ -#include #include #include +#include #include #include #include @@ -123,7 +123,7 @@ /* sanity check */ if (byte_count_max > byte_count) - return(NULL); + return NULL; hubinfo_get(hubv, &hubinfo); @@ -152,7 +152,7 @@ * For now, reject requests that span big windows. */ if ((xtalk_addr % BWIN_SIZE) + byte_count > BWIN_SIZE) - return(NULL); + return NULL; /* Round xtalk address down for big window alignement */ @@ -184,7 +184,7 @@ widget == bw_piomap->hpio_xtalk_info.xp_target) { bw_piomap->hpio_holdcnt++; spin_unlock(&hubinfo->h_bwlock); - return(bw_piomap); + return bw_piomap; } } @@ -264,7 +264,7 @@ done: spin_unlock(&hubinfo->h_bwlock); - return(bw_piomap); + return bw_piomap; } /* @@ -330,18 +330,18 @@ { /* Verify that range can be mapped using the specified piomap */ if (xtalk_addr < hub_piomap->hpio_xtalk_info.xp_xtalk_addr) - return(0); + return 0; if (xtalk_addr + byte_count > ( hub_piomap->hpio_xtalk_info.xp_xtalk_addr + hub_piomap->hpio_xtalk_info.xp_mapsz)) - return(0); + return 0; if (hub_piomap->hpio_flags & HUB_PIOMAP_IS_VALID) - return(hub_piomap->hpio_xtalk_info.xp_kvaddr + - (xtalk_addr % hub_piomap->hpio_xtalk_info.xp_mapsz)); + return hub_piomap->hpio_xtalk_info.xp_kvaddr + + (xtalk_addr % hub_piomap->hpio_xtalk_info.xp_mapsz); else - return(0); + return 0; } @@ -388,9 +388,9 @@ addr = (caddr_t)iaddr; } #endif - return(addr); + return addr; } else - return(0); + return 0; } @@ -425,7 +425,7 @@ if (flags & XTALK_FIXED) dmamap->hdma_flags |= HUB_DMAMAP_IS_FIXED; - return(dmamap); + return dmamap; } /* @@ -467,42 +467,12 @@ } /* There isn't actually any DMA mapping hardware on the hub. */ - return( (PHYS_TO_DMA(paddr)) ); -} - -/* - * Establish a DMA mapping using the resources allocated in a previous dmamap_alloc. - * Return an appropriate crosstalk address list that maps to the specified physical - * address list. - */ -/* ARGSUSED */ -alenlist_t -hub_dmamap_list(hub_dmamap_t hub_dmamap, /* use these mapping resources */ - alenlist_t palenlist, /* map this area of memory */ - unsigned flags) -{ - vertex_hdl_t vhdl; - - ASSERT(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_VALID); - - if (hub_dmamap->hdma_flags & HUB_DMAMAP_USED) { - /* If the map is FIXED, re-use is OK. */ - if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { - char name[MAXDEVNAME]; - vhdl = hub_dmamap->hdma_xtalk_info.xd_dev; - printk(KERN_WARNING "%s: hub_dmamap_list re-uses dmamap\n", vertex_to_name(vhdl, name, MAXDEVNAME)); - } - } else { - hub_dmamap->hdma_flags |= HUB_DMAMAP_USED; - } - - /* There isn't actually any DMA mapping hardware on the hub. */ - return(palenlist); + return (PHYS_TO_DMA(paddr)); } /* * Driver indicates that it has completed whatever DMA it may have started - * after an earlier dmamap_addr or dmamap_list call. + * after an earlier dmamap_addr call. */ void hub_dmamap_done(hub_dmamap_t hub_dmamap) /* done with these mapping resources */ @@ -532,24 +502,7 @@ size_t byte_count, /* length */ unsigned flags) /* defined in dma.h */ { - return( (PHYS_TO_DMA(paddr)) ); -} - -/* - * Translate a list of IP27 addresses and lengths into a list of crosstalk - * addresses and lengths. No actual hardware mapping takes place; the hub - * has no DMA mapping registers -- crosstalk addresses map directly. - */ -/* ARGSUSED */ -alenlist_t -hub_dmatrans_list( vertex_hdl_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - alenlist_t palenlist, /* system address/length list */ - unsigned flags) /* defined in dma.h */ -{ - BUG(); - /* no translation needed */ - return(palenlist); + return (PHYS_TO_DMA(paddr)); } /*ARGSUSED*/ @@ -568,15 +521,6 @@ /* XXX- flush caches, if cache coherency WAR is needed */ } -/*ARGSUSED*/ -void -hub_dmalist_drain( vertex_hdl_t vhdl, - alenlist_t list) -{ - /* XXX- flush caches, if cache coherency WAR is needed */ -} - - /* CONFIGURATION MANAGEMENT */ @@ -609,8 +553,8 @@ { nasid_t nasid = NASID_GET(addr); - if (((__psunsigned_t)addr >= RAW_NODE_SWIN_BASE(nasid, 0)) && - ((__psunsigned_t)addr < RAW_NODE_SWIN_BASE(nasid, 1))) + if (((unsigned long)addr >= RAW_NODE_SWIN_BASE(nasid, 0)) && + ((unsigned long)addr < RAW_NODE_SWIN_BASE(nasid, 1))) return 1; return 0; } @@ -626,8 +570,8 @@ return 1; /* XXX - Assume this is really a small window address */ - if (WIDGETID_GET((__psunsigned_t)addra) == - WIDGETID_GET((__psunsigned_t)addrb)) + if (WIDGETID_GET((unsigned long)addra) == + WIDGETID_GET((unsigned long)addrb)) return 1; return 0; @@ -768,28 +712,25 @@ * crosstalk bus provider. */ xtalk_provider_t hub_provider = { - (xtalk_piomap_alloc_f *) hub_piomap_alloc, - (xtalk_piomap_free_f *) hub_piomap_free, - (xtalk_piomap_addr_f *) hub_piomap_addr, - (xtalk_piomap_done_f *) hub_piomap_done, - (xtalk_piotrans_addr_f *) hub_piotrans_addr, - - (xtalk_dmamap_alloc_f *) hub_dmamap_alloc, - (xtalk_dmamap_free_f *) hub_dmamap_free, - (xtalk_dmamap_addr_f *) hub_dmamap_addr, - (xtalk_dmamap_list_f *) hub_dmamap_list, - (xtalk_dmamap_done_f *) hub_dmamap_done, - (xtalk_dmatrans_addr_f *) hub_dmatrans_addr, - (xtalk_dmatrans_list_f *) hub_dmatrans_list, - (xtalk_dmamap_drain_f *) hub_dmamap_drain, - (xtalk_dmaaddr_drain_f *) hub_dmaaddr_drain, - (xtalk_dmalist_drain_f *) hub_dmalist_drain, - - (xtalk_intr_alloc_f *) hub_intr_alloc, - (xtalk_intr_alloc_f *) hub_intr_alloc_nothd, - (xtalk_intr_free_f *) hub_intr_free, - (xtalk_intr_connect_f *) hub_intr_connect, - (xtalk_intr_disconnect_f *) hub_intr_disconnect, - (xtalk_provider_startup_f *) hub_provider_startup, - (xtalk_provider_shutdown_f *) hub_provider_shutdown, + .piomap_alloc = (xtalk_piomap_alloc_f *) hub_piomap_alloc, + .piomap_free = (xtalk_piomap_free_f *) hub_piomap_free, + .piomap_addr = (xtalk_piomap_addr_f *) hub_piomap_addr, + .piomap_done = (xtalk_piomap_done_f *) hub_piomap_done, + .piotrans_addr = (xtalk_piotrans_addr_f *) hub_piotrans_addr, + + .dmamap_alloc = (xtalk_dmamap_alloc_f *) hub_dmamap_alloc, + .dmamap_free = (xtalk_dmamap_free_f *) hub_dmamap_free, + .dmamap_addr = (xtalk_dmamap_addr_f *) hub_dmamap_addr, + .dmamap_done = (xtalk_dmamap_done_f *) hub_dmamap_done, + .dmatrans_addr = (xtalk_dmatrans_addr_f *) hub_dmatrans_addr, + .dmamap_drain = (xtalk_dmamap_drain_f *) hub_dmamap_drain, + .dmaaddr_drain = (xtalk_dmaaddr_drain_f *) hub_dmaaddr_drain, + + .intr_alloc = (xtalk_intr_alloc_f *) hub_intr_alloc, + .intr_alloc_nothd = (xtalk_intr_alloc_f *) hub_intr_alloc_nothd, + .intr_free = (xtalk_intr_free_f *) hub_intr_free, + .intr_connect = (xtalk_intr_connect_f *) hub_intr_connect, + .intr_disconnect = (xtalk_intr_disconnect_f *) hub_intr_disconnect, + .provider_startup = (xtalk_provider_startup_f *) hub_provider_startup, + .provider_shutdown = (xtalk_provider_shutdown_f *) hub_provider_shutdown, }; --- diff/arch/ia64/sn/io/machvec/pci_bus_cvlink.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/machvec/pci_bus_cvlink.c 2004-02-09 10:39:51.000000000 +0000 @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -22,13 +23,20 @@ static int done_probing; extern irqpda_t *irqpdaindr; -static int pci_bus_map_create(vertex_hdl_t xtalk, char * io_moduleid); +static int pci_bus_map_create(struct pcibr_list_s *softlistp, moduleid_t io_moduleid); vertex_hdl_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); extern void register_pcibr_intr(int irq, pcibr_intr_t intr); -void sn_dma_flush_init(unsigned long start, unsigned long end, int idx, int pin, int slot); +static void sn_dma_flush_init(unsigned long start, + unsigned long end, + int idx, int pin, int slot); extern int cbrick_type_get_nasid(nasid_t); +extern void ioconfig_bus_new_entries(void); +extern void ioconfig_get_busnum(char *, int *); +extern int iomoduleid_get(nasid_t); +extern int pcibr_widget_to_bus(vertex_hdl_t); +extern int isIO9(int); #define IS_OPUS(nasid) (cbrick_type_get_nasid(nasid) == MODULE_OPUSBRICK) #define IS_ALTIX(nasid) (cbrick_type_get_nasid(nasid) == MODULE_CBRICK) @@ -37,7 +45,7 @@ * Init the provider asic for a given device */ -static void +static inline void __init set_pci_provider(struct sn_device_sysdata *device_sysdata) { pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); @@ -69,7 +77,7 @@ * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated * pci bus vertex from the SGI IO Infrastructure. */ -vertex_hdl_t +static inline vertex_hdl_t pci_bus_to_vertex(unsigned char busnum) { @@ -157,16 +165,15 @@ * on the in use pin. This will prevent the race condition between PIO read responses and * DMA writes. */ -void -sn_dma_flush_init(unsigned long start, unsigned long end, int idx, int pin, int slot) { +static void +sn_dma_flush_init(unsigned long start, unsigned long end, int idx, int pin, int slot) +{ nasid_t nasid; unsigned long dnasid; int wid_num; int bus; struct sn_flush_device_list *p; - bridge_t *b; - bridgereg_t dev_sel; - extern int isIO9(int); + void *b; int bwin; int i; @@ -178,8 +185,8 @@ if (flush_nasid_list[nasid].widget_p == NULL) { flush_nasid_list[nasid].widget_p = (struct sn_flush_device_list **)kmalloc((HUB_WIDGET_ID_MAX+1) * sizeof(struct sn_flush_device_list *), GFP_KERNEL); - if (flush_nasid_list[nasid].widget_p <= 0) { - printk("sn_dma_flush_init: Cannot allocate memory for nasid list\n"); + if (!flush_nasid_list[nasid].widget_p) { + printk(KERN_WARNING "sn_dma_flush_init: Cannot allocate memory for nasid list\n"); return; } memset(flush_nasid_list[nasid].widget_p, 0, (HUB_WIDGET_ID_MAX+1) * sizeof(struct sn_flush_device_list *)); @@ -209,8 +216,8 @@ if (flush_nasid_list[nasid].widget_p[wid_num] == NULL) { flush_nasid_list[nasid].widget_p[wid_num] = (struct sn_flush_device_list *)kmalloc( DEV_PER_WIDGET * sizeof (struct sn_flush_device_list), GFP_KERNEL); - if (flush_nasid_list[nasid].widget_p[wid_num] <= 0) { - printk("sn_dma_flush_init: Cannot allocate memory for nasid sub-list\n"); + if (!flush_nasid_list[nasid].widget_p[wid_num]) { + printk(KERN_WARNING "sn_dma_flush_init: Cannot allocate memory for nasid sub-list\n"); return; } memset(flush_nasid_list[nasid].widget_p[wid_num], 0, @@ -243,7 +250,7 @@ break; } } - b = (bridge_t *)(NODE_SWIN_BASE(nasid, wid_num) | (bus << 23) ); + b = (void *)(NODE_SWIN_BASE(nasid, wid_num) | (bus << 23) ); /* If it's IO9, then slot 2 maps to slot 7 and slot 6 maps to slot 8. * To see this is non-trivial. By drawing pictures and reading manuals and talking @@ -267,39 +274,34 @@ if (isIO9(nasid) && ( (IS_ALTIX(nasid) && wid_num == 0xc) || (IS_OPUS(nasid) && wid_num == 0xf) ) && bus == 0) { - if (slot == 2) { - p->force_int_addr = (unsigned long)&b->b_force_always[6].intr; - dev_sel = b->b_int_device; - dev_sel |= (1<<18); - b->b_int_device = dev_sel; + if (pin == 1) { + p->force_int_addr = (unsigned long)pcireg_bridge_force_always_addr_get(b, 6); + pcireg_bridge_intr_device_bit_set(b, (1<<18)); dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); - b->p_int_addr_64[6] = (virt_to_phys(&p->flush_addr) & 0xfffffffff) | - (dnasid << 36) | (0xfUL << 48); - } else if (slot == 3) { /* 12160 SCSI device in IO9 */ - p->force_int_addr = (unsigned long)&b->b_force_always[4].intr; - dev_sel = b->b_int_device; - dev_sel |= (2<<12); - b->b_int_device = dev_sel; + pcireg_bridge_intr_addr_set(b, 6, ((virt_to_phys(&p->flush_addr) & 0xfffffffff) | + (dnasid << 36) | (0xfUL << 48))); + } else if (pin == 2) { /* 12160 SCSI device in IO9 */ + p->force_int_addr = (unsigned long)pcireg_bridge_force_always_addr_get(b, 4); + pcireg_bridge_intr_device_bit_set(b, (2<<12)); dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); - b->p_int_addr_64[4] = (virt_to_phys(&p->flush_addr) & 0xfffffffff) | - (dnasid << 36) | (0xfUL << 48); + pcireg_bridge_intr_addr_set(b, 4, + ((virt_to_phys(&p->flush_addr) & 0xfffffffff) | + (dnasid << 36) | (0xfUL << 48))); } else { /* slot == 6 */ - p->force_int_addr = (unsigned long)&b->b_force_always[7].intr; - dev_sel = b->b_int_device; - dev_sel |= (5<<21); - b->b_int_device = dev_sel; + p->force_int_addr = (unsigned long)pcireg_bridge_force_always_addr_get(b, 7); + pcireg_bridge_intr_device_bit_set(b, (5<<21)); dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); - b->p_int_addr_64[7] = (virt_to_phys(&p->flush_addr) & 0xfffffffff) | - (dnasid << 36) | (0xfUL << 48); + pcireg_bridge_intr_addr_set(b, 7, + ((virt_to_phys(&p->flush_addr) & 0xfffffffff) | + (dnasid << 36) | (0xfUL << 48))); } } else { - p->force_int_addr = (unsigned long)&b->b_force_always[pin + 2].intr; - dev_sel = b->b_int_device; - dev_sel |= ((slot - 1) << ( pin * 3) ); - b->b_int_device = dev_sel; + p->force_int_addr = (unsigned long)pcireg_bridge_force_always_addr_get(b, (pin +2)); + pcireg_bridge_intr_device_bit_set(b, (pin << (pin * 3))); dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); - b->p_int_addr_64[pin + 2] = (virt_to_phys(&p->flush_addr) & 0xfffffffff) | - (dnasid << 36) | (0xfUL << 48); + pcireg_bridge_intr_addr_set(b, (pin + 2), + ((virt_to_phys(&p->flush_addr) & 0xfffffffff) | + (dnasid << 36) | (0xfUL << 48))); } } @@ -310,7 +312,7 @@ * * Other platform specific fixup can also be done here. */ -void +static void __init sn_pci_fixup(int arg) { struct list_head *ln; @@ -321,7 +323,7 @@ pcibr_intr_t intr_handle; pciio_provider_t *pci_provider; vertex_hdl_t device_vertex; - pciio_intr_line_t lines; + pciio_intr_line_t lines = 0; extern int numnodes; int cnode; @@ -357,6 +359,11 @@ pci_bus = pci_bus_b(ln); widget_sysdata = kmalloc(sizeof(struct sn_widget_sysdata), GFP_KERNEL); + if (!widget_sysdata) { + printk(KERN_WARNING "sn_pci_fixup(): Unable to " + "allocate memory for widget_sysdata\n"); + return; + } widget_sysdata->vhdl = pci_bus_to_vertex(pci_bus->number); pci_bus->sysdata = (void *)widget_sysdata; } @@ -394,13 +401,12 @@ device_sysdata = kmalloc(sizeof(struct sn_device_sysdata), GFP_KERNEL); - if (device_sysdata <= 0) { - printk("sn_pci_fixup: Cannot allocate memory for device sysdata\n"); + if (!device_sysdata) { + printk(KERN_WARNING "sn_pci_fixup: Cannot allocate memory for device sysdata\n"); return; } device_sysdata->vhdl = devfn_to_vertex(device_dev->bus->number, device_dev->devfn); - device_sysdata->isa64 = 0; device_dev->sysdata = (void *) device_sysdata; set_pci_provider(device_sysdata); @@ -486,14 +492,22 @@ device_vertex = device_sysdata->vhdl; pci_provider = device_sysdata->pci_provider; + if (!lines) { + continue; + } + irqpdaindr->curr = device_dev; intr_handle = (pci_provider->intr_alloc)(device_vertex, NULL, lines, device_vertex); + if (intr_handle == NULL) { + printk("sn_pci_fixup: pcibr_intr_alloc() failed\n"); + continue; + } irq = intr_handle->bi_irq; irqpdaindr->device_dev[irq] = device_dev; (pci_provider->intr_connect)(intr_handle, (intr_func_t)0, (intr_arg_t)0); device_dev->irq = irq; - register_pcibr_intr(irq, intr_handle); + register_pcibr_intr(irq, (pcibr_intr_t)intr_handle); for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { int ibits = intr_handle->bi_ibits; @@ -507,10 +521,10 @@ for (i=0; i<8; i++) { if (ibits & (1 << i) ) { sn_dma_flush_init(device_dev->resource[idx].start, - device_dev->resource[idx].end, - idx, - i, - PCI_SLOT(device_dev->devfn)); + device_dev->resource[idx].end, + idx, + i, + PCIBR_INFO_SLOT_GET_EXT(pcibr_info_get(device_sysdata->vhdl))); } } } @@ -548,238 +562,132 @@ * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job. * * Linux PCI Bus numbers are assigned from lowest module_id numbers - * (rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to - * HUB_WIDGET_ID_MIN: - * widgetnum 15 gets lower Bus Number than widgetnum 14 etc. - * - * Given 2 modules 001c01 and 001c02 we get the following mappings: - * 001c01, widgetnum 15 = Bus number 0 - * 001c01, widgetnum 14 = Bus number 1 - * 001c02, widgetnum 15 = Bus number 3 - * 001c02, widgetnum 14 = Bus number 4 - * etc. - * - * The rational for starting Bus Number 0 with Widget number 15 is because - * the system boot disks are always connected via Widget 15 Slot 0 of the - * I-brick. Linux creates /dev/sd* devices(naming) strating from Bus Number 0 - * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest - * module id(Master Cnode) of the system. - * + * (rack/slot etc.) */ static int -pci_bus_map_create(vertex_hdl_t xtalk, char * io_moduleid) +pci_bus_map_create(struct pcibr_list_s *softlistp, moduleid_t moduleid) { + + int basebus_num, bus_number; + vertex_hdl_t pci_bus = softlistp->bl_vhdl; + char moduleid_str[16]; - vertex_hdl_t master_node_vertex = NULL; - vertex_hdl_t xwidget = NULL; - vertex_hdl_t pci_bus = NULL; - hubinfo_t hubinfo = NULL; - xwidgetnum_t widgetnum; - char pathname[128]; - graph_error_t rv; - int bus; - int basebus_num; - extern void ioconfig_get_busnum(char *, int *); - - int bus_number; + memset(moduleid_str, 0, 16); + format_module_id(moduleid_str, moduleid, MODULE_FORMAT_BRIEF); + (void) ioconfig_get_busnum((char *)moduleid_str, &basebus_num); /* - * Loop throught this vertex and get the Xwidgets .. + * Assign the correct bus number and also the nasid of this + * pci Xwidget. */ - - - /* PCI devices */ - - for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) { - sprintf(pathname, "%d", widgetnum); - xwidget = NULL; - - /* - * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget - * /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device - */ - rv = hwgraph_traverse(xtalk, pathname, &xwidget); - if ( (rv != GRAPH_SUCCESS) ) { - if (!xwidget) { - continue; - } - } - - sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); - pci_bus = NULL; - if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS) - if (!pci_bus) { - continue; -} - - /* - * Assign the correct bus number and also the nasid of this - * pci Xwidget. - * - * Should not be any race here ... - */ - num_bridges++; - busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus; - - /* - * Get the master node and from there get the NASID. - */ - master_node_vertex = device_master_get(xwidget); - if (!master_node_vertex) { - printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget); - } - - hubinfo_get(master_node_vertex, &hubinfo); - if (!hubinfo) { - printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex); - return(1); - } else { - busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid; - } - - /* - * Pre assign DMA maps needed for 32 Bits Page Map DMA. - */ - busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc( - sizeof(struct pcibr_dmamap_s) * MAX_ATE_MAPS, GFP_KERNEL); - if (!busnum_to_atedmamaps[num_bridges - 1]) - printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget); - - memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, - sizeof(struct pcibr_dmamap_s) * MAX_ATE_MAPS); - + bus_number = basebus_num + pcibr_widget_to_bus(pci_bus); +#ifdef DEBUG + { + char hwpath[MAXDEVNAME] = "\0"; + extern int hwgraph_vertex_name_get(vertex_hdl_t, char *, uint); + + pcibr_soft_t pcibr_soft = softlistp->bl_soft; + hwgraph_vertex_name_get(pci_bus, hwpath, MAXDEVNAME); + printk("%s:\n\tbus_num %d, basebus_num %d, brick_bus %d, " + "bus_vhdl 0x%lx, brick_type %d\n", hwpath, bus_number, + basebus_num, pcibr_widget_to_bus(pci_bus), + (uint64_t)pci_bus, pcibr_soft->bs_bricktype); } +#endif + busnum_to_pcibr_vhdl[bus_number] = pci_bus; /* - * PCIX devices - * We number busses differently for PCI-X devices. - * We start from Lowest Widget on up .. + * Pre assign DMA maps needed for 32 Bits Page Map DMA. */ - - (void) ioconfig_get_busnum((char *)io_moduleid, &basebus_num); - - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { - - /* Do both buses */ - for ( bus = 0; bus < 2; bus++ ) { - sprintf(pathname, "%d", widgetnum); - xwidget = NULL; - - /* - * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget - * /hw/module/001c16/Pbrick/xtalk/8/pci-x/0 is the bus - * /hw/module/001c16/Pbrick/xtalk/8/pci-x/0/1 is device - */ - rv = hwgraph_traverse(xtalk, pathname, &xwidget); - if ( (rv != GRAPH_SUCCESS) ) { - if (!xwidget) { - continue; - } - } - - if ( bus == 0 ) - sprintf(pathname, "%d/"EDGE_LBL_PCIX_0, widgetnum); - else - sprintf(pathname, "%d/"EDGE_LBL_PCIX_1, widgetnum); - pci_bus = NULL; - if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS) - if (!pci_bus) { - continue; - } - - /* - * Assign the correct bus number and also the nasid of this - * pci Xwidget. - * - * Should not be any race here ... - */ - bus_number = basebus_num + bus + io_brick_map_widget(MODULE_PXBRICK, widgetnum); -#ifdef DEBUG - printk("bus_number %d basebus_num %d bus %d io %d\n", - bus_number, basebus_num, bus, - io_brick_map_widget(MODULE_PXBRICK, widgetnum)); -#endif - busnum_to_pcibr_vhdl[bus_number] = pci_bus; - - /* - * Pre assign DMA maps needed for 32 Bits Page Map DMA. - */ - busnum_to_atedmamaps[bus_number] = (void *) kmalloc( - sizeof(struct pcibr_dmamap_s) * MAX_ATE_MAPS, GFP_KERNEL); - if (!busnum_to_atedmamaps[bus_number]) - printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget); - - memset(busnum_to_atedmamaps[bus_number], 0x0, - sizeof(struct pcibr_dmamap_s) * MAX_ATE_MAPS); - } + busnum_to_atedmamaps[bus_number] = (void *) vmalloc( + sizeof(struct pcibr_dmamap_s)*MAX_ATE_MAPS); + if (busnum_to_atedmamaps[bus_number] <= 0) { + printk("pci_bus_map_create: Cannot allocate memory for ate maps\n"); + return -1; } - - return(0); + memset(busnum_to_atedmamaps[bus_number], 0x0, + sizeof(struct pcibr_dmamap_s) * MAX_ATE_MAPS); + return(0); } /* - * pci_bus_to_hcl_cvlink() - This routine is called after SGI IO Infrastructure - * initialization has completed to set up the mappings between Xbridge - * and logical pci bus numbers. We also set up the NASID for each of these - * xbridges. + * pci_bus_to_hcl_cvlink() - This routine is called after SGI IO Infrastructure + * initialization has completed to set up the mappings between PCI BRIDGE + * ASIC and logical pci bus numbers. * * Must be called before pci_init() is invoked. */ int pci_bus_to_hcl_cvlink(void) { + int i; + extern pcibr_list_p pcibr_list; - vertex_hdl_t devfs_hdl = NULL; - vertex_hdl_t xtalk = NULL; - int rv = 0; - char name[256]; - char tmp_name[256]; - int i, ii, j; - char *brick_name; - extern void ioconfig_bus_new_entries(void); - - /* - * Figure out which IO Brick is connected to the Compute Bricks. - */ for (i = 0; i < nummodules; i++) { - extern int iomoduleid_get(nasid_t); - moduleid_t iobrick_id; - nasid_t nasid = -1; - int nodecnt; - int n = 0; - - nodecnt = modules[i]->nodecnt; - for ( n = 0; n < nodecnt; n++ ) { - nasid = cnodeid_to_nasid(modules[i]->nodes[n]); - iobrick_id = iomoduleid_get(nasid); - if ((int)iobrick_id > 0) { /* Valid module id */ - char name[12]; - memset(name, 0, 12); - format_module_id((char *)&(modules[i]->io[n].moduleid), iobrick_id, MODULE_FORMAT_BRIEF); + struct pcibr_list_s *softlistp = pcibr_list; + struct pcibr_list_s *first_in_list = NULL; + struct pcibr_list_s *last_in_list = NULL; + + /* Walk the list of pcibr_soft structs looking for matches */ + while (softlistp) { + struct pcibr_soft_s *pcibr_soft = softlistp->bl_soft; + moduleid_t moduleid; + + /* Is this PCI bus associated with this moduleid? */ + moduleid = NODE_MODULEID( + NASID_TO_COMPACT_NODEID(pcibr_soft->bs_nasid)); + if (modules[i]->id == moduleid) { + struct pcibr_list_s *new_element; + + new_element = kmalloc(sizeof (struct pcibr_soft_s), GFP_KERNEL); + if (new_element == NULL) { + printk("%s: Couldn't allocate memory\n",__FUNCTION__); + return -ENOMEM; + } + new_element->bl_soft = softlistp->bl_soft; + new_element->bl_vhdl = softlistp->bl_vhdl; + new_element->bl_next = NULL; + + /* list empty so just put it on the list */ + if (first_in_list == NULL) { + first_in_list = new_element; + last_in_list = new_element; + softlistp = softlistp->bl_next; + continue; + } + + /* + * BASEIO IObricks attached to a module have + * a higher priority than non BASEIO IOBricks + * when it comes to persistant pci bus + * numbering, so put them on the front of the + * list. + */ + if (isIO9(pcibr_soft->bs_nasid)) { + new_element->bl_next = first_in_list; + first_in_list = new_element; + } else { + last_in_list->bl_next = new_element; + last_in_list = new_element; + } } + softlistp = softlistp->bl_next; } - } - devfs_hdl = hwgraph_path_to_vertex("hw/module"); - for (i = 0; i < nummodules ; i++) { - for ( j = 0; j < 2; j++ ) { - if ( j == 0 ) - brick_name = EDGE_LBL_PXBRICK; - else - brick_name = EDGE_LBL_IXBRICK; - - for ( ii = 0; ii < 2 ; ii++ ) { - memset(name, 0, 256); - memset(tmp_name, 0, 256); - format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF); - sprintf(tmp_name, "/slab/%d/%s/xtalk", geo_slab(modules[i]->geoid[ii]), brick_name); - strcat(name, tmp_name); - xtalk = NULL; - rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); - if ( rv == 0 ) - pci_bus_map_create(xtalk, (char *)&(modules[i]->io[ii].moduleid)); + /* + * We now have a list of all the pci bridges associated with + * the module_id, modules[i]. Call pci_bus_map_create() for + * each pci bridge + */ + softlistp = first_in_list; + while (softlistp) { + moduleid_t iobrick; + struct pcibr_list_s *next = softlistp->bl_next; + iobrick = iomoduleid_get(softlistp->bl_soft->bs_nasid); + pci_bus_map_create(softlistp, iobrick); + kfree(softlistp); + softlistp = next; } - } } /* @@ -806,6 +714,11 @@ return 0; /* + * This is needed to avoid bounce limit checks in the blk layer + */ + ia64_max_iommu_merge_mask = ~PAGE_MASK; + + /* * set pci_raw_ops, etc. */ sn_pci_fixup(0); --- diff/arch/ia64/sn/io/machvec/pci_dma.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/machvec/pci_dma.c 2004-02-09 10:39:51.000000000 +0000 @@ -138,6 +138,8 @@ if (!(cpuaddr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size)))) return NULL; + memset(cpuaddr, 0x0, size); + /* physical addr. of the memory we just got */ phys_addr = __pa(cpuaddr); @@ -154,7 +156,8 @@ *dma_handle = pcibr_dmatrans_addr(vhdl, NULL, phys_addr, size, PCIIO_DMA_CMD | PCIIO_DMA_A64); else { - dma_map = pcibr_dmamap_alloc(vhdl, NULL, size, PCIIO_DMA_CMD); + dma_map = pcibr_dmamap_alloc(vhdl, NULL, size, PCIIO_DMA_CMD | + MINIMAL_ATE_FLAG(phys_addr, size)); if (dma_map) { *dma_handle = (dma_addr_t) pcibr_dmamap_addr(dma_map, phys_addr, size); @@ -248,18 +251,6 @@ phys_addr = __pa((unsigned long)page_address(sg->page) + sg->offset); /* - * Handle the most common case: 64 bit cards. This - * call should always succeed. - */ - if (IS_PCIA64(hwdev)) { - sg->dma_address = pcibr_dmatrans_addr(vhdl, NULL, phys_addr, - sg->length, - PCIIO_DMA_DATA | PCIIO_DMA_A64); - sg->dma_length = sg->length; - continue; - } - - /* * Handle 32-63 bit cards via direct mapping */ if (IS_PCI32G(hwdev)) { @@ -385,13 +376,6 @@ dma_addr = 0; phys_addr = __pa(ptr); - if (IS_PCIA64(hwdev)) { - /* This device supports 64 bit DMA addresses. */ - dma_addr = pcibr_dmatrans_addr(vhdl, NULL, phys_addr, size, - PCIIO_DMA_DATA | PCIIO_DMA_A64); - return dma_addr; - } - /* * Devices that support 32 bit to 63 bit DMA addresses get * 32 bit DMA addresses. @@ -410,7 +394,8 @@ * let's use the PMU instead. */ dma_map = NULL; - dma_map = pcibr_dmamap_alloc(vhdl, NULL, size, PCIIO_DMA_DATA); + dma_map = pcibr_dmamap_alloc(vhdl, NULL, size, PCIIO_DMA_DATA | + MINIMAL_ATE_FLAG(phys_addr, size)); if (!dma_map) { printk(KERN_ERR "pci_map_single: Unable to allocate anymore " --- diff/arch/ia64/sn/io/platform_init/sgi_io_init.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/platform_init/sgi_io_init.c 2004-02-09 10:39:51.000000000 +0000 @@ -131,7 +131,7 @@ klhwg_add_all_modules(hwgraph_root); klhwg_add_all_nodes(hwgraph_root); - for (cnode = 0; cnode < numnodes; cnode++) { + for (cnode = 0; cnode < numionodes; cnode++) { extern void per_hub_init(cnodeid_t); per_hub_init(cnode); } --- diff/arch/ia64/sn/io/sn2/klconflib.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/klconflib.c 2004-02-09 10:39:51.000000000 +0000 @@ -31,6 +31,8 @@ #define DBG(x...) #endif /* DEBUG_KLGRAPH */ +extern int numionodes; + lboard_t *root_lboard[MAX_COMPACT_NODES]; static int hasmetarouter; @@ -38,13 +40,13 @@ char brick_types[MAX_BRICK_TYPES + 1] = "crikxdpn%#=vo^34567890123456789..."; lboard_t * -find_lboard(lboard_t *start, unsigned char brd_type) +find_lboard_any(lboard_t *start, unsigned char brd_type) { /* Search all boards stored on this node. */ while (start) { if (start->brd_type == brd_type) return start; - start = KLCF_NEXT(start); + start = KLCF_NEXT_ANY(start); } /* Didn't find it. */ @@ -52,19 +54,59 @@ } lboard_t * -find_lboard_class(lboard_t *start, unsigned char brd_type) +find_lboard_nasid(lboard_t *start, nasid_t nasid, unsigned char brd_type) { - /* Search all boards stored on this node. */ + + while (start) { + if ((start->brd_type == brd_type) && + (start->brd_nasid == nasid)) + return start; + + if (numionodes == numnodes) + start = KLCF_NEXT_ANY(start); + else + start = KLCF_NEXT(start); + } + + /* Didn't find it. */ + return (lboard_t *)NULL; +} + +lboard_t * +find_lboard_class_any(lboard_t *start, unsigned char brd_type) +{ + /* Search all boards stored on this node. */ while (start) { if (KLCLASS(start->brd_type) == KLCLASS(brd_type)) return start; - start = KLCF_NEXT(start); + start = KLCF_NEXT_ANY(start); + } + + /* Didn't find it. */ + return (lboard_t *)NULL; +} + +lboard_t * +find_lboard_class_nasid(lboard_t *start, nasid_t nasid, unsigned char brd_type) +{ + /* Search all boards stored on this node. */ + while (start) { + if (KLCLASS(start->brd_type) == KLCLASS(brd_type) && + (start->brd_nasid == nasid)) + return start; + + if (numionodes == numnodes) + start = KLCF_NEXT_ANY(start); + else + start = KLCF_NEXT(start); } /* Didn't find it. */ return (lboard_t *)NULL; } + + klinfo_t * find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type) { @@ -116,20 +158,6 @@ return (lboard_t *)NULL; } -lboard_t * -find_lboard_module(lboard_t *start, geoid_t geoid) -{ - /* Search all boards stored on this node. */ - while (start) { - if (geo_cmp(start->brd_geoid, geoid)) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - /* * Convert a NIC name to a name for use in the hardware graph. */ @@ -218,7 +246,7 @@ /* * look for boards that might contain an xbow or xbridge */ - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW); + brd = find_lboard_nasid((lboard_t *)KL_CONFIG_INFO(nasid), nasid, KLTYPE_IOBRICK_XBOW); if (brd == NULL) return 0; if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) @@ -285,40 +313,6 @@ #define MHZ 1000000 - -/* Get the canonical hardware graph name for the given pci component - * on the given io board. - */ -void -device_component_canonical_name_get(lboard_t *brd, - klinfo_t *component, - char *name) -{ - slotid_t slot; - char board_name[20]; - - ASSERT(brd); - - /* Convert the [ CLASS | TYPE ] kind of slotid - * into a string - */ - slot = brd->brd_slot; - - /* Get the io board name */ - if (!brd || (brd->brd_sversion < 2)) { - strcpy(name, EDGE_LBL_XWIDGET); - } else { - nic_name_convert(brd->brd_name, board_name); - } - - /* Give out the canonical name of the pci device*/ - sprintf(name, - "/dev/hw/"EDGE_LBL_MODULE "/%x/"EDGE_LBL_SLAB"/%d/" - EDGE_LBL_SLOT"/%s/"EDGE_LBL_PCI"/%d", - geo_module(brd->brd_geoid), geo_slab(brd->brd_geoid), - board_name, KLCF_BRIDGE_W_ID(component)); -} - /* * Get the serial number of the main component of a board * Returns 0 if a valid serial number is found @@ -506,7 +500,7 @@ format_module_id(char *buffer, moduleid_t m, int fmt) { int rack, position; - char brickchar; + unsigned char brickchar; rack = MODULE_GET_RACK(m); ASSERT(MODULE_GET_BTYPE(m) < MAX_BRICK_TYPES); @@ -560,112 +554,21 @@ } -/* - * Parse a module id, in either brief or long form. - * Returns < 0 on error. - * The long form does not include a brick type, so it defaults to 0 (CBrick) - */ -int -parse_module_id(char *buffer) -{ - unsigned int v, rack, bay, type, form; - moduleid_t m; - char c; - - if (strstr(buffer, EDGE_LBL_RACK "/") == buffer) { - form = MODULE_FORMAT_LONG; - buffer += strlen(EDGE_LBL_RACK "/"); - - /* A long module ID must be exactly 5 non-template chars. */ - if (strlen(buffer) != strlen("/" EDGE_LBL_RPOS "/") + 5) - return -1; - } - else { - form = MODULE_FORMAT_BRIEF; - - /* A brief module id must be exactly 6 characters */ - if (strlen(buffer) != 6) - return -2; - } - - /* The rack number must be exactly 3 digits */ - if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && isdigit(buffer[2]))) - return -3; - - rack = 0; - v = *buffer++ - '0'; - if (v > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) - return -4; - RACK_ADD_CLASS(rack, v); - - v = *buffer++ - '0'; - if (v > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) - return -5; - RACK_ADD_GROUP(rack, v); - - v = *buffer++ - '0'; - /* rack numbers are 1-based */ - if (v-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) - return -6; - RACK_ADD_NUM(rack, v); - - if (form == MODULE_FORMAT_BRIEF) { - /* Next should be a module type character. Accept ucase or lcase. */ - c = *buffer++; - if (!isalpha(c)) - return -7; - - /* strchr() returns a pointer into brick_types[], or NULL */ - type = (unsigned int)(strchr(brick_types, tolower(c)) - brick_types); - if (type > MODULE_BTYPE_MASK >> MODULE_BTYPE_SHFT) - return -8; - } - else { - /* Hardcode the module type, and skip over the boilerplate */ - type = MODULE_CBRICK; - - if (strstr(buffer, "/" EDGE_LBL_RPOS "/") != buffer) - return -9; - - buffer += strlen("/" EDGE_LBL_RPOS "/"); - } - - /* The bay number is last. Make sure it's exactly two digits */ - - if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && !buffer[2])) - return -10; - - bay = 10 * (buffer[0] - '0') + (buffer[1] - '0'); - - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) - return -11; - - m = RBT_TO_MODULE(rack, bay, type); - - /* avoid sign extending the moduleid_t */ - return (int)(unsigned short)m; -} - int cbrick_type_get_nasid(nasid_t nasid) { - lboard_t *brd; moduleid_t module; - uint type; int t; - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - module = geo_module(brd->brd_geoid); - type = (module & MODULE_BTYPE_MASK) >> MODULE_BTYPE_SHFT; - /* convert brick_type to lower case */ - if ((type >= 'A') && (type <= 'Z')) - type = type - 'A' + 'a'; - - /* convert to a module.h brick type */ - for( t = 0; t < MAX_BRICK_TYPES; t++ ) { - if( brick_types[t] == type ) { - return t; - } - } + module = iomoduleid_get(nasid); + if (module < 0 ) { + return MODULE_CBRICK; + } + t = MODULE_GET_BTYPE(module); + if ((char)t == 'o') { + return MODULE_OPUSBRICK; + } else { + return MODULE_CBRICK; + } return -1; } --- diff/arch/ia64/sn/io/sn2/klgraph.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/klgraph.c 2004-02-09 10:39:51.000000000 +0000 @@ -43,7 +43,7 @@ hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv); - HWGRAPH_DEBUG((__FILE__, __FUNCTION__,__LINE__, myhubv, NULL, "Created path for hub vertex for Shub node.\n")); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, myhubv, NULL, "Created path for hub vertex for Shub node.\n"); rc = device_master_set(myhubv, node_vertex); if (rc) { @@ -71,7 +71,7 @@ snprintf(name, 120, "%s/%s/%c", EDGE_LBL_DISABLED, EDGE_LBL_CPU, 'a' + cpu->cpu_info.physid); (void) hwgraph_path_add(node_vertex, name, &my_cpu); - HWGRAPH_DEBUG((__FILE__, __FUNCTION__,__LINE__, my_cpu, NULL, "Created path for disabled cpu slice.\n")); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, my_cpu, NULL, "Created path for disabled cpu slice.\n"); mark_cpuvertex_as_cpu(my_cpu, cpu_id); device_master_set(my_cpu, node_vertex); @@ -98,7 +98,7 @@ (void) hwgraph_path_add(node_vertex, name, &my_cpu); - HWGRAPH_DEBUG((__FILE__, __FUNCTION__,__LINE__, my_cpu, NULL, "Created path for active cpu slice.\n")); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, my_cpu, NULL, "Created path for active cpu slice.\n"); mark_cpuvertex_as_cpu(my_cpu, cpu_id); device_master_set(my_cpu, node_vertex); @@ -107,7 +107,7 @@ if (hwgraph_edge_get(node_vertex, EDGE_LBL_CPU, &cpu_dir) == GRAPH_SUCCESS) { snprintf(name, 120, "%c", 'a' + cpu->cpu_info.physid); (void) hwgraph_edge_add(cpu_dir, my_cpu, name); - HWGRAPH_DEBUG((__FILE__, __FUNCTION__,__LINE__, cpu_dir, my_cpu, "Created % from vhdl1 to vhdl2.\n", name)); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, cpu_dir, my_cpu, "Created % from vhdl1 to vhdl2.\n", name); } } @@ -124,8 +124,9 @@ /*REFERENCED*/ graph_error_t err; - if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW)) == NULL) - return; + if (!(brd = find_lboard_nasid((lboard_t *)KL_CONFIG_INFO(nasid), + nasid, KLTYPE_IOBRICK_XBOW))) + return; if (KL_CONFIG_DUPLICATE_BOARD(brd)) return; @@ -165,7 +166,7 @@ return; } - HWGRAPH_DEBUG((__FILE__, __FUNCTION__, __LINE__, xbow_v, NULL, "Created path for xtalk.\n")); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, xbow_v, NULL, "Created path for xtalk.\n"); xswitch_vertex_init(xbow_v); @@ -200,7 +201,7 @@ vertex_hdl_t cpu_dir; nasid = COMPACT_TO_NASID_NODEID(cnode); - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + brd = find_lboard_any((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); ASSERT(brd); /* Generate a hardware graph path for this board. */ @@ -211,7 +212,7 @@ return; } - HWGRAPH_DEBUG((__FILE__, __FUNCTION__, __LINE__, node_vertex, NULL, "Created path for SHUB node.\n")); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, node_vertex, NULL, "Created path for SHUB node.\n"); hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); ASSERT(hub); if(hub->hub_info.flags & KLINFO_ENABLE) @@ -249,7 +250,7 @@ printk("klhwg_add_node: Cannot create CPU directory\n"); return; } - HWGRAPH_DEBUG((__FILE__, __FUNCTION__, __LINE__, cpu_dir, NULL, "Created cpu directiry on SHUB node.\n")); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, cpu_dir, NULL, "Created cpu directiry on SHUB node.\n"); } @@ -280,7 +281,7 @@ for (cnode = 0; cnode < numnodes; cnode++) { nasid = COMPACT_TO_NASID_NODEID(cnode); - brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), + brd = find_lboard_class_any((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_ROUTER); if (!brd) @@ -304,10 +305,10 @@ "failed. Path == %s", path_buffer); return; } - HWGRAPH_DEBUG((__FILE__, __FUNCTION__, __LINE__, node_vertex, NULL, "Created router path.\n")); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, node_vertex, NULL, "Created router path.\n"); /* Find the rest of the routers stored on this node. */ - } while ( (brd = find_lboard_class(KLCF_NEXT(brd), + } while ( (brd = find_lboard_class_any(KLCF_NEXT_ANY(brd), KLTYPE_ROUTER)) ); } @@ -399,7 +400,7 @@ path_buffer, dest_path, (void *)dest_hndl, rc); return; } - HWGRAPH_DEBUG((__FILE__, __FUNCTION__, __LINE__, router_hndl, dest_hndl, "Created edge %s from vhdl1 to vhdl2.\n", dest_path)); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, router_hndl, dest_hndl, "Created edge %s from vhdl1 to vhdl2.\n", dest_path); } } @@ -414,7 +415,7 @@ for (cnode = 0; cnode < numnodes; cnode++) { nasid = COMPACT_TO_NASID_NODEID(cnode); - brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), + brd = find_lboard_class_any((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_ROUTER); if (!brd) @@ -428,7 +429,7 @@ cnode, nasid); /* Find the rest of the routers stored on this node. */ - } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) ); + } while ( (brd = find_lboard_class_any(KLCF_NEXT_ANY(brd), KLTYPE_ROUTER)) ); } } @@ -452,8 +453,7 @@ for (cnode = 0; cnode < numionodes; cnode++) { nasid = COMPACT_TO_NASID_NODEID(cnode); - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - ASSERT(brd); + brd = find_lboard_any((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); ASSERT(hub); @@ -492,14 +492,14 @@ rc = hwgraph_path_add(hub_hndl, EDGE_LBL_INTERCONNECT, &hub_hndl); - HWGRAPH_DEBUG((__FILE__, __FUNCTION__, __LINE__, hub_hndl, NULL, "Created link path.\n")); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, hub_hndl, NULL, "Created link path.\n"); sprintf(buf,"%s/%s",path_buffer,EDGE_LBL_INTERCONNECT); rc = hwgraph_traverse(hwgraph_root, buf, &hub_hndl); sprintf(buf,"%d",port); rc = hwgraph_edge_add(hub_hndl, dest_hndl, buf); - HWGRAPH_DEBUG((__FILE__, __FUNCTION__, __LINE__, hub_hndl, dest_hndl, "Created edge %s from vhdl1 to vhdl2.\n", buf)); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, hub_hndl, dest_hndl, "Created edge %s from vhdl1 to vhdl2.\n", buf); if (rc != GRAPH_SUCCESS) { printk("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n", @@ -511,69 +511,6 @@ } } -/* Store the pci/vme disabled board information as extended administrative - * hints which can later be used by the drivers using the device/driver - * admin interface. - */ -static void __init -klhwg_device_disable_hints_add(void) -{ - cnodeid_t cnode; /* node we are looking at */ - nasid_t nasid; /* nasid of the node */ - lboard_t *board; /* board we are looking at */ - int comp_index; /* component index */ - klinfo_t *component; /* component in the board we are - * looking at - */ - char device_name[MAXDEVNAME]; - - for(cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - board = (lboard_t *)KL_CONFIG_INFO(nasid); - /* Check out all the board info stored on a node */ - while(board) { - /* No need to look at duplicate boards or non-io - * boards - */ - if (KL_CONFIG_DUPLICATE_BOARD(board) || - KLCLASS(board->brd_type) != KLCLASS_IO) { - board = KLCF_NEXT(board); - continue; - } - /* Check out all the components of a board */ - for (comp_index = 0; - comp_index < KLCF_NUM_COMPS(board); - comp_index++) { - component = KLCF_COMP(board,comp_index); - /* If the component is enabled move on to - * the next component - */ - if (KLCONFIG_INFO_ENABLED(component)) - continue; - /* NOTE : Since the prom only supports - * the disabling of pci devices the following - * piece of code makes sense. - * Make sure that this assumption is valid - */ - /* This component is disabled. Store this - * hint in the extended device admin table - */ - /* Get the canonical name of the pci device */ - device_component_canonical_name_get(board, - component, - device_name); -#ifdef DEBUG - printf("%s DISABLED\n",device_name); -#endif - } - /* go to the next board info stored on this - * node - */ - board = KLCF_NEXT(board); - } - } -} - void __init klhwg_add_all_modules(vertex_hdl_t hwgraph_root) { @@ -596,7 +533,7 @@ rc = hwgraph_path_add(hwgraph_root, name, &module_vhdl); ASSERT(rc == GRAPH_SUCCESS); rc = rc; - HWGRAPH_DEBUG((__FILE__, __FUNCTION__, __LINE__, module_vhdl, NULL, "Created module path.\n")); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, module_vhdl, NULL, "Created module path.\n"); hwgraph_fastinfo_set(module_vhdl, (arbitrary_info_t) modules[cm]); @@ -608,7 +545,7 @@ rc = hwgraph_path_add(hwgraph_root, name, &vhdl); ASSERT_ALWAYS(rc == GRAPH_SUCCESS); rc = rc; - HWGRAPH_DEBUG((__FILE__, __FUNCTION__, __LINE__, vhdl, NULL, "Created L1 path.\n")); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, vhdl, NULL, "Created L1 path.\n"); hwgraph_info_add_LBL(vhdl, INFO_LBL_ELSC, (arbitrary_info_t)1); @@ -637,10 +574,4 @@ klhwg_add_all_routers(hwgraph_root); klhwg_connect_routers(hwgraph_root); klhwg_connect_hubs(hwgraph_root); - - /* Go through the entire system's klconfig - * to figure out which pci components have been disabled - */ - klhwg_device_disable_hints_add(); - } --- diff/arch/ia64/sn/io/sn2/ml_iograph.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/ml_iograph.c 2004-02-09 10:39:51.000000000 +0000 @@ -46,8 +46,9 @@ int rc; xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL); - if (xvolinfo <= 0 ) { - printk("xswitch_vertex_init: out of memory\n"); + if (!xvolinfo) { + printk(KERN_WARNING "xswitch_vertex_init(): Unable to " + "allocate memory\n"); return; } memset(xvolinfo, 0, sizeof(struct xswitch_vol_s)); @@ -239,30 +240,29 @@ static void early_probe_for_widget(vertex_hdl_t hubv, xwidget_hwid_t hwid) { - hubreg_t llp_csr_reg; nasid_t nasid; hubinfo_t hubinfo; + hubreg_t llp_csr_reg; + widgetreg_t widget_id; + int result = 0; + + hwid->part_num = XWIDGET_PART_NUM_NONE; + hwid->rev_num = XWIDGET_REV_NUM_NONE; + hwid->mfg_num = XWIDGET_MFG_NUM_NONE; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); - /* - * If link is up, read the widget's part number. - * A direct connect widget must respond to widgetnum=0. - */ - if (llp_csr_reg & IIO_LLP_CSR_IS_UP) { - /* TBD: Put hub into "indirect" mode */ - /* - * We're able to read from a widget because our hub's - * WIDGET_ID was set up earlier. - */ - widgetreg_t widget_id = *(volatile widgetreg_t *) - (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); + if (!(llp_csr_reg & IIO_LLP_CSR_IS_UP)) + return; - DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id, - (volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) ); + /* Read the Cross-Talk Widget Id on the other end */ + result = snia_badaddr_val((volatile void *) + (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID), + 4, (void *) &widget_id); + if (result == 0) { /* Found something connected */ hwid->part_num = XWIDGET_PART_NUM(widget_id); hwid->rev_num = XWIDGET_REV_NUM(widget_id); hwid->mfg_num = XWIDGET_MFG_NUM(widget_id); @@ -344,13 +344,12 @@ return; } - board = find_lboard_class( - (lboard_t *)KL_CONFIG_INFO(nasid), - KLCLASS_IOBRICK); + board = find_lboard_class_nasid( (lboard_t *)KL_CONFIG_INFO(nasid), + nasid, KLCLASS_IOBRICK); if (!board && NODEPDA(cnode)->xbow_peer != INVALID_NASID) { - board = find_lboard_class( - (lboard_t *)KL_CONFIG_INFO( NODEPDA(cnode)->xbow_peer), - KLCLASS_IOBRICK); + board = find_lboard_class_nasid( + (lboard_t *)KL_CONFIG_INFO( NODEPDA(cnode)->xbow_peer), + NODEPDA(cnode)->xbow_peer, KLCLASS_IOBRICK); } if (board) { @@ -365,7 +364,7 @@ { lboard_t *brd; - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + brd = find_lboard_any((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); if ( brd != (lboard_t *)0 ) { board->brd_geoid = brd->brd_geoid; } @@ -584,10 +583,9 @@ } else { void *bridge; - extern uint64_t pcireg_control_get(void *); bridge = (void *)NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0); - npdap->basew_id = pcireg_control_get(bridge) & WIDGET_WIDGET_ID; + npdap->basew_id = pcireg_bridge_control_get(bridge) & WIDGET_WIDGET_ID; printk(" ****io_init_node: Unknown Widget Part Number 0x%x Widget ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, (void *)hubv); return; @@ -764,7 +762,7 @@ /* Look for brick prefix in table */ for (i = 0; i < num_bricks; i++) { if (brick_type == io_brick_tab[i].ibm_type) - return(io_brick_tab[i].ibm_map_wid[widget_num]); + return io_brick_tab[i].ibm_map_wid[widget_num]; } return 0; --- diff/arch/ia64/sn/io/sn2/module.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/module.c 2004-02-09 10:39:51.000000000 +0000 @@ -139,7 +139,7 @@ /* * record brick serial number */ - board = find_lboard((lboard_t *) KL_CONFIG_INFO(host_nasid), KLTYPE_SNIA); + board = find_lboard_nasid((lboard_t *) KL_CONFIG_INFO(host_nasid), host_nasid, KLTYPE_SNIA); if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) { @@ -152,8 +152,8 @@ m->snum_valid = 1; } - board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), - KLTYPE_IOBRICK_XBOW); + board = find_lboard_nasid((lboard_t *) KL_CONFIG_INFO(nasid), + nasid, KLTYPE_IOBRICK_XBOW); if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) return 0; @@ -185,6 +185,7 @@ nasid_t nasid; int nserial; module_t *m; + extern int numionodes; DPRINTF("*******module_init\n"); @@ -196,14 +197,40 @@ */ for (node = 0; node < numnodes; node++) { nasid = COMPACT_TO_NASID_NODEID(node); - - board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); + board = find_lboard_nasid((lboard_t *) KL_CONFIG_INFO(nasid), nasid, KLTYPE_SNIA); ASSERT(board); - HWGRAPH_DEBUG((__FILE__, __FUNCTION__, __LINE__, NULL, NULL, "Found Shub lboard 0x%lx nasid 0x%x cnode 0x%x \n", (unsigned long)board, (int)nasid, (int)node)); + HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, NULL, NULL, "Found Shub lboard 0x%lx nasid 0x%x cnode 0x%x \n", (unsigned long)board, (int)nasid, (int)node); m = module_add_node(board->brd_geoid, node); if (! m->snum_valid && module_probe_snum(m, nasid, nasid)) nserial++; } + + /* + * Second scan, look for headless/memless board hosted by compute nodes. + */ + for (node = numnodes; node < numionodes; node++) { + nasid_t nasid; + char serial_number[16]; + + nasid = COMPACT_TO_NASID_NODEID(node); + board = find_lboard_nasid((lboard_t *) KL_CONFIG_INFO(nasid), + nasid, KLTYPE_SNIA); + ASSERT(board); + + HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, NULL, NULL, "Found headless/memless lboard 0x%lx node %d nasid %d cnode %d\n", (unsigned long)board, node, (int)nasid, (int)node); + + m = module_add_node(board->brd_geoid, node); + + /* + * Get and initialize the serial number. + */ + board_serial_number_get( board, serial_number ); + if( serial_number[0] != '\0' ) { + encode_str_serial( serial_number, m->snum.snum_str ); + m->snum_valid = 1; + nserial++; + } + } } --- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c 2004-02-09 10:39:51.000000000 +0000 @@ -17,106 +17,13 @@ /* * functions */ -int pcibr_init_ext_ate_ram(bridge_t *); -int pcibr_ate_alloc(pcibr_soft_t, int); -void pcibr_ate_free(pcibr_soft_t, int, int); -bridge_ate_t pcibr_flags_to_ate(unsigned); -bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int); -unsigned ate_freeze(pcibr_dmamap_t pcibr_dmamap, -#if PCIBR_FREEZE_TIME - unsigned *freeze_time_ptr, -#endif - unsigned *cmd_regs); -void ate_write(pcibr_soft_t pcibr_soft, bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate); -void ate_thaw(pcibr_dmamap_t pcibr_dmamap, - int ate_index, -#if PCIBR_FREEZE_TIME - bridge_ate_t ate, - int ate_total, - unsigned freeze_time_start, -#endif - unsigned *cmd_regs, - unsigned s); +int pcibr_ate_alloc(pcibr_soft_t, int, struct resource *); +void pcibr_ate_free(pcibr_soft_t, int, int, struct resource *); +bridge_ate_t pcibr_flags_to_ate(pcibr_soft_t, unsigned); +bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int); +void ate_write(pcibr_soft_t, int, int, bridge_ate_t); - -/* Convert from ssram_bits in control register to number of SSRAM entries */ -#define ATE_NUM_ENTRIES(n) _ate_info[n] - -/* Possible choices for number of ATE entries in Bridge's SSRAM */ -static int _ate_info[] = -{ - 0, /* 0 entries */ - 8 * 1024, /* 8K entries */ - 16 * 1024, /* 16K entries */ - 64 * 1024 /* 64K entries */ -}; - -#define ATE_NUM_SIZES (sizeof(_ate_info) / sizeof(int)) -#define ATE_PROBE_VALUE 0x0123456789abcdefULL - -/* - * Determine the size of this bridge's external mapping SSRAM, and set - * the control register appropriately to reflect this size, and initialize - * the external SSRAM. - */ -int -pcibr_init_ext_ate_ram(bridge_t *bridge) -{ - int largest_working_size = 0; - int num_entries, entry; - int i, j; - bridgereg_t old_enable, new_enable; - - /* Probe SSRAM to determine its size. */ - old_enable = bridge->b_int_enable; - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - bridge->b_int_enable = new_enable; - - for (i = 1; i < ATE_NUM_SIZES; i++) { - /* Try writing a value */ - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; - - /* Guard against wrap */ - for (j = 1; j < i; j++) - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(j) - 1] = 0; - - /* See if value was written */ - if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) - largest_working_size = i; - } - bridge->b_int_enable = old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - - bridge->b_wid_control = (bridge->b_wid_control - & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) - | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); - bridge->b_wid_control; /* inval addr bug war */ - - num_entries = ATE_NUM_ENTRIES(largest_working_size); - - if (pcibr_debug_mask & PCIBR_DEBUG_ATE) { - if (num_entries) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, NULL, - "bridge at 0x%x: clearing %d external ATEs\n", - bridge, num_entries)); - } else { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, NULL, - "bridge at 0x%x: no external ATE RAM found\n", - bridge)); - } - } - - /* Initialize external mapping entries */ - for (entry = 0; entry < num_entries; entry++) - bridge->b_ext_ate_ram[entry] = 0; - - return (num_entries); -} +int pcibr_invalidate_ate; /* by default don't invalidate ATE on free */ /* * Allocate "count" contiguous Bridge Address Translation Entries @@ -127,56 +34,48 @@ * Return the start index on success, -1 on failure. */ int -pcibr_ate_alloc(pcibr_soft_t pcibr_soft, int count) +pcibr_ate_alloc(pcibr_soft_t pcibr_soft, int count, struct resource *res) { int status = 0; - struct resource *new_res; - struct resource **allocated_res; + unsigned long flag; - new_res = (struct resource *) kmalloc( sizeof(struct resource), GFP_ATOMIC); - memset(new_res, 0, sizeof(*new_res)); - status = allocate_resource( &pcibr_soft->bs_int_ate_resource, new_res, + memset(res, 0, sizeof(struct resource)); + flag = pcibr_lock(pcibr_soft); + status = allocate_resource( &pcibr_soft->bs_int_ate_resource, res, count, pcibr_soft->bs_int_ate_resource.start, pcibr_soft->bs_int_ate_resource.end, 1, NULL, NULL); - - if ( status && (pcibr_soft->bs_ext_ate_resource.end != 0) ) { - status = allocate_resource( &pcibr_soft->bs_ext_ate_resource, new_res, - count, pcibr_soft->bs_ext_ate_resource.start, - pcibr_soft->bs_ext_ate_resource.end, 1, - NULL, NULL); - if (status) { - new_res->start = -1; - } - } - if (status) { /* Failed to allocate */ - kfree(new_res); + pcibr_unlock(pcibr_soft, flag); return -1; } /* Save the resource for freeing */ - allocated_res = (struct resource **)(((unsigned long)pcibr_soft->bs_allocated_ate_res) + new_res->start * sizeof( unsigned long)); - *allocated_res = new_res; + pcibr_unlock(pcibr_soft, flag); - return new_res->start; + return res->start; } void -pcibr_ate_free(pcibr_soft_t pcibr_soft, int index, int count) -/* Who says there's no such thing as a free meal? :-) */ +pcibr_ate_free(pcibr_soft_t pcibr_soft, int index, int count, struct resource *res) { - struct resource **allocated_res; + bridge_ate_t ate; int status = 0; + unsigned long flags; - allocated_res = (struct resource **)(((unsigned long)pcibr_soft->bs_allocated_ate_res) + index * sizeof(unsigned long)); + if (pcibr_invalidate_ate) { + /* For debugging purposes, clear the valid bit in the ATE */ + ate = *pcibr_ate_addr(pcibr_soft, index); + ate_write(pcibr_soft, index, count, (ate & ~ATE_V)); + } - status = release_resource(*allocated_res); + flags = pcibr_lock(pcibr_soft); + status = release_resource(res); + pcibr_unlock(pcibr_soft, flags); if (status) BUG(); /* Ouch .. */ - kfree(*allocated_res); } @@ -185,7 +84,7 @@ * into Bridge-specific Address Translation Entry attribute bits. */ bridge_ate_t -pcibr_flags_to_ate(unsigned flags) +pcibr_flags_to_ate(pcibr_soft_t pcibr_soft, unsigned flags) { bridge_ate_t attributes; @@ -232,6 +131,11 @@ if (flags & PCIBR_NOPRECISE) attributes &= ~ATE_PREC; + /* In PCI-X mode, Prefetch & Precise not supported */ + if (IS_PCIX(pcibr_soft)) { + attributes &= ~(ATE_PREC | ATE_PREF); + } + return (attributes); } @@ -243,189 +147,33 @@ pcibr_ate_addr(pcibr_soft_t pcibr_soft, int ate_index) { - bridge_t *bridge = pcibr_soft->bs_base; - - return (ate_index < pcibr_soft->bs_int_ate_size) - ? &(bridge->b_int_ate_ram[ate_index].wr) - : &(bridge->b_ext_ate_ram[ate_index]); -} - -/* We are starting to get more complexity - * surrounding writing ATEs, so pull - * the writing code into this new function. - */ - -#if PCIBR_FREEZE_TIME -#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, &freeze_time, cmd_regs) -#else -#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, cmd_regs) -#endif - -unsigned -ate_freeze(pcibr_dmamap_t pcibr_dmamap, -#if PCIBR_FREEZE_TIME - unsigned *freeze_time_ptr, -#endif - unsigned *cmd_regs) -{ - pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; -#ifdef LATER - int dma_slot = pcibr_dmamap->bd_slot; -#endif - int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; - int slot; - - unsigned long s; - unsigned cmd_reg; - volatile unsigned *cmd_lwa; - unsigned cmd_lwd; - - if (!ext_ates) - return 0; - - /* Bridge Hardware Bug WAR #484930: - * Bridge can't handle updating External ATEs - * while DMA is occurring that uses External ATEs, - * even if the particular ATEs involved are disjoint. - */ - - /* need to prevent anyone else from - * unfreezing the grant while we - * are working; also need to prevent - * this thread from being interrupted - * to keep PCI grant freeze time - * at an absolute minimum. - */ - s = pcibr_lock(pcibr_soft); - -#ifdef LATER - /* just in case pcibr_dmamap_done was not called */ - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { - pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) - atomic_dec(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); - xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); - } -#endif /* LATER */ -#if PCIBR_FREEZE_TIME - *freeze_time_ptr = get_timestamp(); -#endif - - cmd_lwa = 0; - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) - if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { - cmd_reg = pcibr_soft-> - bs_slot[slot]. - bss_cmd_shadow; - if (cmd_reg & PCI_CMD_BUS_MASTER) { - cmd_lwa = pcibr_soft-> - bs_slot[slot]. - bss_cmd_pointer; - cmd_lwd = cmd_reg ^ PCI_CMD_BUS_MASTER; - cmd_lwa[0] = cmd_lwd; - } - cmd_regs[slot] = cmd_reg; - } else - cmd_regs[slot] = 0; - - if (cmd_lwa) { - bridge_t *bridge = pcibr_soft->bs_base; - - /* Read the last master bit that has been cleared. This PIO read - * on the PCI bus is to ensure the completion of any DMAs that - * are due to bus requests issued by PCI devices before the - * clearing of master bits. - */ - cmd_lwa[0]; - - /* Flush all the write buffers in the bridge */ - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { - /* Flush the write buffer associated with this - * PCI device which might be using dma map RAM. - */ - bridge->b_wr_req_buf[slot].reg; - } - } + if (ate_index < pcibr_soft->bs_int_ate_size) { + return (pcireg_int_ate_addr(pcibr_soft, ate_index)); + } else { + printk("pcibr_ate_addr(): INVALID ate_index 0x%x", ate_index); + return (bridge_ate_p)0; } - return s; -} - -void -ate_write(pcibr_soft_t pcibr_soft, - bridge_ate_p ate_ptr, - int ate_count, - bridge_ate_t ate) -{ - while (ate_count-- > 0) { - *ate_ptr++ = ate; - ate += IOPGSIZE; - } } -#if PCIBR_FREEZE_TIME -#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, ate, ate_total, freeze_time, cmd_regs, s) -#else -#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, cmd_regs, s) -#endif - +/* + * Write the ATE. + */ void -ate_thaw(pcibr_dmamap_t pcibr_dmamap, - int ate_index, -#if PCIBR_FREEZE_TIME - bridge_ate_t ate, - int ate_total, - unsigned freeze_time_start, -#endif - unsigned *cmd_regs, - unsigned s) +ate_write(pcibr_soft_t pcibr_soft, int ate_index, int count, bridge_ate_t ate) { - pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; - int dma_slot = pcibr_dmamap->bd_slot; - int slot; - bridge_t *bridge = pcibr_soft->bs_base; - int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; - - unsigned cmd_reg; - -#if PCIBR_FREEZE_TIME - unsigned freeze_time; - static unsigned max_freeze_time = 0; - static unsigned max_ate_total; -#endif - - if (!ext_ates) - return; - - /* restore cmd regs */ - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - if ((cmd_reg = cmd_regs[slot]) & PCI_CMD_BUS_MASTER) { - pcibr_slot_config_set(bridge, slot, PCI_CFG_COMMAND/4, cmd_reg); + while (count-- > 0) { + if (ate_index < pcibr_soft->bs_int_ate_size) { + pcireg_int_ate_set(pcibr_soft, ate_index, ate); + PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_soft->bs_vhdl, + "ate_write(): ate_index=0x%x, ate=0x%lx\n", + ate_index, (uint64_t)ate)); + } else { + printk("ate_write(): INVALID ate_index 0x%x", ate_index); + return; } + ate_index++; + ate += IOPGSIZE; } - pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_BUSY; - atomic_inc(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); - -#if PCIBR_FREEZE_TIME - freeze_time = get_timestamp() - freeze_time_start; - if ((max_freeze_time < freeze_time) || - (max_ate_total < ate_total)) { - if (max_freeze_time < freeze_time) - max_freeze_time = freeze_time; - if (max_ate_total < ate_total) - max_ate_total = ate_total; - pcibr_unlock(pcibr_soft, s); - printk( "%s: pci freeze time %d usec for %d ATEs\n" - "\tfirst ate: %R\n", - pcibr_soft->bs_name, - freeze_time * 1000 / 1250, - ate_total, - ate, ate_bits); - } else -#endif - pcibr_unlock(pcibr_soft, s); + pcireg_tflush_get(pcibr_soft); /* wait until Bridge PIO complete */ } --- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c 2004-02-09 10:39:51.000000000 +0000 @@ -34,22 +34,21 @@ * the 32bit word that contains the "offset" byte. */ cfg_p -pcibr_func_config_addr(bridge_t *bridge, pciio_bus_t bus, pciio_slot_t slot, +pcibr_func_config_addr(pcibr_soft_t soft, pciio_bus_t bus, pciio_slot_t slot, pciio_function_t func, int offset) { /* * Type 1 config space */ if (bus > 0) { - bridge->b_pci_cfg = ((bus << 16) | (slot << 11)); - return &bridge->b_type1_cfg.f[func].l[(offset)]; + pcireg_type1_cntr_set(soft, ((bus << 16) | (slot << 11))); + return (pcireg_type1_cfg_addr(soft, func, offset)); } /* * Type 0 config space */ - slot++; - return &bridge->b_type0_cfg_dev[slot].f[func].l[offset]; + return (pcireg_type0_cfg_addr(soft, slot, func, offset)); } /* @@ -58,59 +57,21 @@ * 32bit word that contains the "offset" byte. */ cfg_p -pcibr_slot_config_addr(bridge_t *bridge, pciio_slot_t slot, int offset) +pcibr_slot_config_addr(pcibr_soft_t soft, pciio_slot_t slot, int offset) { - return pcibr_func_config_addr(bridge, 0, slot, 0, offset); -} - -/* - * Return config space data for given slot / offset - */ -unsigned -pcibr_slot_config_get(bridge_t *bridge, pciio_slot_t slot, int offset) -{ - cfg_p cfg_base; - - cfg_base = pcibr_slot_config_addr(bridge, slot, 0); - return (do_pcibr_config_get(cfg_base, offset, sizeof(unsigned))); -} - -/* - * Return config space data for given slot / func / offset - */ -unsigned -pcibr_func_config_get(bridge_t *bridge, pciio_slot_t slot, - pciio_function_t func, int offset) -{ - cfg_p cfg_base; - - cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0); - return (do_pcibr_config_get(cfg_base, offset, sizeof(unsigned))); -} - -/* - * Set config space data for given slot / offset - */ -void -pcibr_slot_config_set(bridge_t *bridge, pciio_slot_t slot, - int offset, unsigned val) -{ - cfg_p cfg_base; - - cfg_base = pcibr_slot_config_addr(bridge, slot, 0); - do_pcibr_config_set(cfg_base, offset, sizeof(unsigned), val); + return pcibr_func_config_addr(soft, 0, slot, 0, offset); } /* * Set config space data for given slot / func / offset */ void -pcibr_func_config_set(bridge_t *bridge, pciio_slot_t slot, +pcibr_func_config_set(pcibr_soft_t soft, pciio_slot_t slot, pciio_function_t func, int offset, unsigned val) { cfg_p cfg_base; - cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0); + cfg_base = pcibr_func_config_addr(soft, 0, slot, func, 0); do_pcibr_config_set(cfg_base, offset, sizeof(unsigned), val); } @@ -124,8 +85,6 @@ pciio_bus_t pciio_bus; pciio_slot_t pciio_slot; pciio_function_t pciio_func; - pcibr_soft_t pcibr_soft; - bridge_t *bridge; cfg_p cfgbase = (cfg_p)0; pciio_info_t pciio_info; @@ -164,11 +123,7 @@ pciio_func = PCI_TYPE1_FUNC(reg); } - pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - - bridge = pcibr_soft->bs_base; - - cfgbase = pcibr_func_config_addr(bridge, + cfgbase = pcibr_func_config_addr((pcibr_soft_t) pcibr_info->f_mfast, pciio_bus, pciio_slot, pciio_func, 0); return cfgbase; --- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c 2004-02-09 10:39:51.000000000 +0000 @@ -30,68 +30,17 @@ * based bricks use the corelet id. * -pcibr_debug_slot is the pci slot you want to trace. */ -uint32_t pcibr_debug_mask = 0x0; /* 0x00000000 to disable */ +uint32_t pcibr_debug_mask; /* 0x00000000 to disable */ static char *pcibr_debug_module = "all"; /* 'all' for all modules */ static int pcibr_debug_widget = -1; /* '-1' for all widgets */ static int pcibr_debug_slot = -1; /* '-1' for all slots */ -/* kbrick widgetnum-to-bus layout */ -int p_busnum[MAX_PORT_NUM] = { /* widget# */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ - 2, /* 0x8 */ - 1, /* 0x9 */ - 0, 0, /* 0xa - 0xb */ - 5, /* 0xc */ - 6, /* 0xd */ - 4, /* 0xe */ - 3, /* 0xf */ -}; - -char *pci_space[] = {"NONE", - "ROM", - "IO", - "", - "MEM", - "MEM32", - "MEM64", - "CFG", - "WIN0", - "WIN1", - "WIN2", - "WIN3", - "WIN4", - "WIN5", - "", - "BAD"}; - #if PCIBR_SOFT_LIST -pcibr_list_p pcibr_list = 0; +pcibr_list_p pcibr_list; #endif -extern int hwgraph_vertex_name_get(vertex_hdl_t vhdl, char *buf, uint buflen); -extern long atoi(register char *p); -extern cnodeid_t nodevertex_to_cnodeid(vertex_hdl_t vhdl); -extern char *dev_to_name(vertex_hdl_t dev, char *buf, uint buflen); -extern struct map *atemapalloc(uint64_t); -extern void atefree(struct map *, size_t, uint64_t); -extern void atemapfree(struct map *); -extern pciio_dmamap_t get_free_pciio_dmamap(vertex_hdl_t); -extern void free_pciio_dmamap(pcibr_dmamap_t); -extern void xwidget_error_register(vertex_hdl_t, error_handler_f *, error_handler_arg_t); - -#define ATE_WRITE() ate_write(pcibr_soft, ate_ptr, ate_count, ate) -#if PCIBR_FREEZE_TIME -#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, &freeze_time, cmd_regs) -#else -#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, cmd_regs) -#endif /* PCIBR_FREEZE_TIME */ - -#if PCIBR_FREEZE_TIME -#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, ate, ate_total, freeze_time, cmd_regs, s) -#else -#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, cmd_regs, s) -#endif +extern char *pci_space[]; /* ===================================================================== * Function Table of Contents @@ -102,46 +51,35 @@ * perhaps bust this file into smaller chunks. */ -extern int do_pcibr_rrb_free_all(pcibr_soft_t, bridge_t *, pciio_slot_t); +extern void do_pcibr_rrb_free_all(pcibr_soft_t, pciio_slot_t); extern void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int); +extern void pcibr_rrb_alloc_more(pcibr_soft_t pcibr_soft, int slot, + int vchan, int more_rrbs); extern int pcibr_wrb_flush(vertex_hdl_t); extern int pcibr_rrb_alloc(vertex_hdl_t, int *, int *); -extern void pcibr_rrb_flush(vertex_hdl_t); +void pcibr_rrb_alloc_more(pcibr_soft_t, int, int, int); -static int pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, bridgereg_t); -void pcibr_release_device(pcibr_soft_t, pciio_slot_t, bridgereg_t); +extern void pcibr_rrb_flush(vertex_hdl_t); -extern void pcibr_setwidint(xtalk_intr_t); -extern void pcibr_clearwidint(bridge_t *); +static int pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, uint64_t); +void pcibr_release_device(pcibr_soft_t, pciio_slot_t, uint64_t); extern iopaddr_t pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t, pciio_space_t, int, int, int); +extern int hwgraph_vertex_name_get(vertex_hdl_t vhdl, char *buf, + uint buflen); -int pcibr_attach(vertex_hdl_t); -int pcibr_attach2(vertex_hdl_t, bridge_t *, vertex_hdl_t, - int, pcibr_soft_t *); int pcibr_detach(vertex_hdl_t); +void pcibr_directmap_init(pcibr_soft_t); int pcibr_pcix_rbars_calc(pcibr_soft_t); -extern int pcibr_init_ext_ate_ram(bridge_t *); -extern int pcibr_ate_alloc(pcibr_soft_t, int); -extern void pcibr_ate_free(pcibr_soft_t, int, int); +extern int pcibr_ate_alloc(pcibr_soft_t, int, struct resource *); +extern void pcibr_ate_free(pcibr_soft_t, int, int, struct resource *); +extern pciio_dmamap_t get_free_pciio_dmamap(vertex_hdl_t); +extern void free_pciio_dmamap(pcibr_dmamap_t); extern int pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl); -extern unsigned ate_freeze(pcibr_dmamap_t pcibr_dmamap, -#if PCIBR_FREEZE_TIME - unsigned *freeze_time_ptr, -#endif - unsigned *cmd_regs); -extern void ate_write(pcibr_soft_t pcibr_soft, bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate); -extern void ate_thaw(pcibr_dmamap_t pcibr_dmamap, int ate_index, -#if PCIBR_FREEZE_TIME - bridge_ate_t ate, - int ate_total, - unsigned freeze_time_start, -#endif - unsigned *cmd_regs, - unsigned s); +extern void ate_write(pcibr_soft_t, int, int, bridge_ate_t); pcibr_info_t pcibr_info_get(vertex_hdl_t); @@ -156,7 +94,7 @@ void pcibr_piospace_free(vertex_hdl_t, pciio_space_t, iopaddr_t, size_t); static iopaddr_t pcibr_flags_to_d64(unsigned, pcibr_soft_t); -extern bridge_ate_t pcibr_flags_to_ate(unsigned); +extern bridge_ate_t pcibr_flags_to_ate(pcibr_soft_t, unsigned); pcibr_dmamap_t pcibr_dmamap_alloc(vertex_hdl_t, device_desc_t, size_t, unsigned); void pcibr_dmamap_free(pcibr_dmamap_t); @@ -168,77 +106,20 @@ iopaddr_t pcibr_dmatrans_addr(vertex_hdl_t, device_desc_t, paddr_t, size_t, unsigned); void pcibr_dmamap_drain(pcibr_dmamap_t); void pcibr_dmaaddr_drain(vertex_hdl_t, paddr_t, size_t); -void pcibr_dmalist_drain(vertex_hdl_t, alenlist_t); iopaddr_t pcibr_dmamap_pciaddr_get(pcibr_dmamap_t); -extern unsigned pcibr_intr_bits(pciio_info_t info, - pciio_intr_line_t lines, int nslots); -extern pcibr_intr_t pcibr_intr_alloc(vertex_hdl_t, device_desc_t, pciio_intr_line_t, vertex_hdl_t); -extern void pcibr_intr_free(pcibr_intr_t); -extern void pcibr_setpciint(xtalk_intr_t); -extern int pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t); -extern void pcibr_intr_disconnect(pcibr_intr_t); - -extern vertex_hdl_t pcibr_intr_cpu_get(pcibr_intr_t); -extern void pcibr_intr_func(intr_arg_t); - -extern void print_bridge_errcmd(uint32_t, char *); - -extern void pcibr_error_dump(pcibr_soft_t); -extern uint32_t pcibr_errintr_group(uint32_t); -extern void pcibr_pioerr_check(pcibr_soft_t); -extern void pcibr_error_intr_handler(int, void *, struct pt_regs *); - -extern int pcibr_addr_toslot(pcibr_soft_t, iopaddr_t, pciio_space_t *, iopaddr_t *, pciio_function_t *); -extern void pcibr_error_cleanup(pcibr_soft_t, int); -extern void pcibr_device_disable(pcibr_soft_t, int); -extern int pcibr_pioerror(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *); -extern int pcibr_dmard_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *); -extern int pcibr_dmawr_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *); -extern int pcibr_error_handler(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *); -extern int pcibr_error_handler_wrapper(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *); void pcibr_provider_startup(vertex_hdl_t); void pcibr_provider_shutdown(vertex_hdl_t); int pcibr_reset(vertex_hdl_t); pciio_endian_t pcibr_endian_set(vertex_hdl_t, pciio_endian_t, pciio_endian_t); -int pcibr_priority_bits_set(pcibr_soft_t, pciio_slot_t, pciio_priority_t); -pciio_priority_t pcibr_priority_set(vertex_hdl_t, pciio_priority_t); int pcibr_device_flags_set(vertex_hdl_t, pcibr_device_flags_t); -extern cfg_p pcibr_config_addr(vertex_hdl_t, unsigned); -extern uint64_t pcibr_config_get(vertex_hdl_t, unsigned, unsigned); -extern void pcibr_config_set(vertex_hdl_t, unsigned, unsigned, uint64_t); - -extern pcibr_hints_t pcibr_hints_get(vertex_hdl_t, int); -extern void pcibr_hints_fix_rrbs(vertex_hdl_t); -extern void pcibr_hints_dualslot(vertex_hdl_t, pciio_slot_t, pciio_slot_t); -extern void pcibr_hints_intr_bits(vertex_hdl_t, pcibr_intr_bits_f *); -extern void pcibr_set_rrb_callback(vertex_hdl_t, rrb_alloc_funct_t); -extern void pcibr_hints_handsoff(vertex_hdl_t); -extern void pcibr_hints_subdevs(vertex_hdl_t, pciio_slot_t, uint64_t); - -extern int pcibr_slot_info_init(vertex_hdl_t,pciio_slot_t); extern int pcibr_slot_info_free(vertex_hdl_t,pciio_slot_t); -extern int pcibr_slot_info_return(pcibr_soft_t, pciio_slot_t, - pcibr_slot_info_resp_t); -extern void pcibr_slot_func_info_return(pcibr_info_h, int, - pcibr_slot_func_info_resp_t); -extern int pcibr_slot_addr_space_init(vertex_hdl_t,pciio_slot_t); -extern int pcibr_slot_pcix_rbar_init(pcibr_soft_t, pciio_slot_t); -extern int pcibr_slot_device_init(vertex_hdl_t, pciio_slot_t); -extern int pcibr_slot_guest_info_init(vertex_hdl_t,pciio_slot_t); -extern int pcibr_slot_call_device_attach(vertex_hdl_t, - pciio_slot_t, int); -extern int pcibr_slot_call_device_detach(vertex_hdl_t, - pciio_slot_t, int); -extern int pcibr_slot_attach(vertex_hdl_t, pciio_slot_t, int, - char *, int *); extern int pcibr_slot_detach(vertex_hdl_t, pciio_slot_t, int, char *, int *); -extern int pcibr_slot_initial_rrb_alloc(vertex_hdl_t, pciio_slot_t); -extern int pcibr_initial_rrb(vertex_hdl_t, pciio_slot_t, pciio_slot_t); +pciio_businfo_t pcibr_businfo_get(vertex_hdl_t); /* ===================================================================== * Device(x) register management @@ -256,33 +137,23 @@ pcibr_try_set_device(pcibr_soft_t pcibr_soft, pciio_slot_t slot, unsigned flags, - bridgereg_t mask) + uint64_t mask) { - bridge_t *bridge; pcibr_soft_slot_t slotp; - bridgereg_t old; - bridgereg_t new; - bridgereg_t chg; - bridgereg_t bad; - bridgereg_t badpmu; - bridgereg_t badd32; - bridgereg_t badd64; - bridgereg_t fix; - unsigned long s; - bridgereg_t xmask; - - xmask = mask; - if (mask == BRIDGE_DEV_PMU_BITS) - xmask = XBRIDGE_DEV_PMU_BITS; - if (mask == BRIDGE_DEV_D64_BITS) - xmask = XBRIDGE_DEV_D64_BITS; + uint64_t old; + uint64_t new; + uint64_t chg; + uint64_t bad; + uint64_t badpmu; + uint64_t badd32; + uint64_t badd64; + uint64_t fix; + unsigned long s; slotp = &pcibr_soft->bs_slot[slot]; s = pcibr_lock(pcibr_soft); - bridge = pcibr_soft->bs_base; - old = slotp->bss_device; /* figure out what the desired @@ -390,21 +261,21 @@ * PIC, can cause problems for 32-bit devices. */ if (mask == BRIDGE_DEV_D64_BITS && - PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) { - if (flags & PCIBR_VCHAN1) { - new |= BRIDGE_DEV_VIRTUAL_EN; - xmask |= BRIDGE_DEV_VIRTUAL_EN; - } + PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) { + if (flags & PCIBR_VCHAN1) { + new |= BRIDGE_DEV_VIRTUAL_EN; + mask |= BRIDGE_DEV_VIRTUAL_EN; + } } /* PIC BRINGUP WAR (PV# 878674): Don't allow 64bit PIO accesses */ - if (IS_PIC_SOFT(pcibr_soft) && (flags & PCIBR_64BIT) && + if ((flags & PCIBR_64BIT) && PCIBR_WAR_ENABLED(PV878674, pcibr_soft)) { new &= ~(1ull << 22); } chg = old ^ new; /* what are we changing, */ - chg &= xmask; /* of the interesting bits */ + chg &= mask; /* of the interesting bits */ if (chg) { @@ -476,9 +347,10 @@ pcibr_unlock(pcibr_soft, s); return 0; } - bridge->b_device[slot].reg = new; + + pcireg_device_set(pcibr_soft, slot, new); slotp->bss_device = new; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + pcireg_tflush_get(pcibr_soft); /* wait until Bridge PIO complete */ pcibr_unlock(pcibr_soft, s); PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl, @@ -489,7 +361,7 @@ void pcibr_release_device(pcibr_soft_t pcibr_soft, pciio_slot_t slot, - bridgereg_t mask) + uint64_t mask) { pcibr_soft_slot_t slotp; unsigned long s; @@ -508,22 +380,6 @@ pcibr_unlock(pcibr_soft, s); } -/* - * flush write gather buffer for slot - */ -static void -pcibr_device_write_gather_flush(pcibr_soft_t pcibr_soft, - pciio_slot_t slot) -{ - bridge_t *bridge; - unsigned long s; - volatile uint32_t wrf; - s = pcibr_lock(pcibr_soft); - bridge = pcibr_soft->bs_base; - - wrf = bridge->b_wr_req_buf[slot].reg; - pcibr_unlock(pcibr_soft, s); -} /* ===================================================================== * Bridge (pcibr) "Device Driver" entry points @@ -535,7 +391,7 @@ { vertex_hdl_t pcibr_vhdl = file->f_dentry->d_fsdata; pcibr_soft_t pcibr_soft; - bridge_t *bridge; + void *bridge; unsigned long phys_addr; int error = 0; @@ -547,7 +403,7 @@ error = io_remap_page_range(vma, phys_addr, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot); - return(error); + return error; } /* @@ -683,7 +539,6 @@ vertex_hdl_t pcibr_vhdl; pciio_slot_t slot; pcibr_soft_t pcibr_soft; - bridge_t *bridge; int count_vchan0, count_vchan1; unsigned long s; int error_call; @@ -695,7 +550,6 @@ slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge = pcibr_soft->bs_base; /* Clear all the hardware xtalk resources for this device */ xtalk_widgetdev_shutdown(pcibr_soft->bs_conn, slot); @@ -718,7 +572,7 @@ pcibr_soft->bs_rrb_valid[slot][VCHAN3]; /* Free the rrbs allocated to this slot, both the normal & virtual */ - do_pcibr_rrb_free_all(pcibr_soft, bridge, slot); + do_pcibr_rrb_free_all(pcibr_soft, slot); count_vchan0 = pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0]; count_vchan1 = pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN1]; @@ -741,7 +595,7 @@ if (error_call) error = error_call; - return(error); + return error; } @@ -823,951 +677,6 @@ } } -/* - * build a convenience link path in the - * form of "...//bus/" - * - * returns 1 on success, 0 otherwise - * - * depends on hwgraph separator == '/' - */ -int -pcibr_bus_cnvlink(vertex_hdl_t f_c) -{ - char dst[MAXDEVNAME]; - char *dp = dst; - char *cp, *xp; - int widgetnum; - char pcibus[8]; - vertex_hdl_t nvtx, svtx; - int rv; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, f_c, "pcibr_bus_cnvlink\n")); - - if (GRAPH_SUCCESS != hwgraph_vertex_name_get(f_c, dst, MAXDEVNAME)) - return 0; - - /* dst example == /hw/module/001c02/Pbrick/xtalk/8/pci/direct */ - - /* find the widget number */ - xp = strstr(dst, "/"EDGE_LBL_XTALK"/"); - if (xp == NULL) - return 0; - widgetnum = simple_strtoul(xp+7, NULL, 0); - if (widgetnum < XBOW_PORT_8 || widgetnum > XBOW_PORT_F) - return 0; - - /* remove "/pci/direct" from path */ - cp = strstr(dst, "/" EDGE_LBL_PCI "/" EDGE_LBL_DIRECT); - if (cp == NULL) - return 0; - *cp = (char)NULL; - - /* get the vertex for the widget */ - if (GRAPH_SUCCESS != hwgraph_traverse(NULL, dp, &svtx)) - return 0; - - *xp = (char)NULL; /* remove "/xtalk/..." from path */ - - /* dst example now == /hw/module/001c02/Pbrick */ - - /* get the bus number */ - strcat(dst, "/"); - strcat(dst, EDGE_LBL_BUS); - sprintf(pcibus, "%d", p_busnum[widgetnum]); - - /* link to bus to widget */ - rv = hwgraph_path_add(NULL, dp, &nvtx); - if (GRAPH_SUCCESS == rv) - rv = hwgraph_edge_add(nvtx, svtx, pcibus); - - return (rv == GRAPH_SUCCESS); -} - - -/* - * pcibr_attach: called every time the crosstalk - * infrastructure is asked to initialize a widget - * that matches the part number we handed to the - * registration routine above. - */ -/*ARGSUSED */ -int -pcibr_attach(vertex_hdl_t xconn_vhdl) -{ - /* REFERENCED */ - graph_error_t rc; - vertex_hdl_t pcibr_vhdl; - bridge_t *bridge; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, xconn_vhdl, "pcibr_attach\n")); - - bridge = (bridge_t *) - xtalk_piotrans_addr(xconn_vhdl, NULL, - 0, sizeof(bridge_t), 0); - /* - * Create the vertex for the PCI bus, which we - * will also use to hold the pcibr_soft and - * which will be the "master" vertex for all the - * pciio connection points we will hang off it. - * This needs to happen before we call nic_bridge_vertex_info - * as we are some of the *_vmc functions need access to the edges. - * - * Opening this vertex will provide access to - * the Bridge registers themselves. - */ - rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl); - ASSERT(rc == GRAPH_SUCCESS); - - pciio_provider_register(pcibr_vhdl, &pcibr_provider); - pciio_provider_startup(pcibr_vhdl); - - return pcibr_attach2(xconn_vhdl, bridge, pcibr_vhdl, 0, NULL); -} - - -/*ARGSUSED */ -int -pcibr_attach2(vertex_hdl_t xconn_vhdl, bridge_t *bridge, - vertex_hdl_t pcibr_vhdl, int busnum, pcibr_soft_t *ret_softp) -{ - /* REFERENCED */ - vertex_hdl_t ctlr_vhdl; - bridgereg_t id; - int rev; - pcibr_soft_t pcibr_soft; - pcibr_info_t pcibr_info; - xwidget_info_t info; - xtalk_intr_t xtalk_intr; - int slot; - int ibit; - vertex_hdl_t noslot_conn; - char devnm[MAXDEVNAME], *s; - pcibr_hints_t pcibr_hints; - uint64_t int_enable; - picreg_t int_enable_64; - unsigned rrb_fixed = 0; - -#if PCI_FBBE - int fast_back_to_back_enable; -#endif - nasid_t nasid; - int iobrick_type_get_nasid(nasid_t nasid); - int iomoduleid_get(nasid_t nasid); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, - "pcibr_attach2: bridge=0x%p, busnum=%d\n", bridge, busnum)); - - ctlr_vhdl = NULL; - ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, 0, - 0, 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - (struct file_operations *)&pcibr_fops, (void *)pcibr_vhdl); - ASSERT(ctlr_vhdl != NULL); - - /* - * Get the hint structure; if some NIC callback - * marked this vertex as "hands-off" then we - * just return here, before doing anything else. - */ - pcibr_hints = pcibr_hints_get(xconn_vhdl, 0); - - if (pcibr_hints && pcibr_hints->ph_hands_off) - return -1; /* generic operations disabled */ - - id = bridge->b_wid_id; - rev = XWIDGET_PART_REV_NUM(id); - - hwgraph_info_add_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, (arbitrary_info_t) rev); - - /* - * allocate soft state structure, fill in some - * fields, and hook it up to our vertex. - */ - pcibr_soft = kmalloc(sizeof(*(pcibr_soft)), GFP_KERNEL); - if (ret_softp) - *ret_softp = pcibr_soft; - if (!pcibr_soft) - return -1; - - memset(pcibr_soft, 0, sizeof *pcibr_soft); - pcibr_soft_set(pcibr_vhdl, pcibr_soft); - pcibr_soft->bs_conn = xconn_vhdl; - pcibr_soft->bs_vhdl = pcibr_vhdl; - pcibr_soft->bs_base = bridge; - pcibr_soft->bs_rev_num = rev; - pcibr_soft->bs_intr_bits = (pcibr_intr_bits_f *)pcibr_intr_bits; - - pcibr_soft->bs_min_slot = 0; /* lowest possible slot# */ - pcibr_soft->bs_max_slot = 7; /* highest possible slot# */ - pcibr_soft->bs_busnum = busnum; - pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_PIC; - switch(pcibr_soft->bs_bridge_type) { - case PCIBR_BRIDGETYPE_BRIDGE: - pcibr_soft->bs_int_ate_size = BRIDGE_INTERNAL_ATES; - pcibr_soft->bs_bridge_mode = 0; /* speed is not available in bridge */ - break; - case PCIBR_BRIDGETYPE_PIC: - pcibr_soft->bs_min_slot = 0; - pcibr_soft->bs_max_slot = 3; - pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES; - pcibr_soft->bs_bridge_mode = - (((bridge->p_wid_stat_64 & PIC_STAT_PCIX_SPEED) >> 33) | - ((bridge->p_wid_stat_64 & PIC_STAT_PCIX_ACTIVE) >> 33)); - - /* We have to clear PIC's write request buffer to avoid parity - * errors. See PV#854845. - */ - { - int i; - - for (i=0; i < PIC_WR_REQ_BUFSIZE; i++) { - bridge->p_wr_req_lower[i] = 0; - bridge->p_wr_req_upper[i] = 0; - bridge->p_wr_req_parity[i] = 0; - } - } - - break; - case PCIBR_BRIDGETYPE_XBRIDGE: - pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES; - pcibr_soft->bs_bridge_mode = - ((bridge->b_wid_control & BRIDGE_CTRL_PCI_SPEED) >> 3); - break; - } - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, - "pcibr_attach2: pcibr_soft=0x%x, mode=0x%x\n", - pcibr_soft, pcibr_soft->bs_bridge_mode)); - pcibr_soft->bsi_err_intr = 0; - - /* Bridges up through REV C - * are unable to set the direct - * byteswappers to BYTE_STREAM. - */ - if (pcibr_soft->bs_rev_num <= BRIDGE_PART_REV_C) { - pcibr_soft->bs_pio_end_io = PCIIO_WORD_VALUES; - pcibr_soft->bs_pio_end_mem = PCIIO_WORD_VALUES; - } -#if PCIBR_SOFT_LIST - /* - * link all the pcibr_soft structs - */ - { - pcibr_list_p self; - - self = kmalloc(sizeof(*(self)), GFP_KERNEL); - if (!self) - return -1; - memset(self, 0, sizeof(*(self))); - self->bl_soft = pcibr_soft; - self->bl_vhdl = pcibr_vhdl; - self->bl_next = pcibr_list; - pcibr_list = self; - } -#endif /* PCIBR_SOFT_LIST */ - - /* - * get the name of this bridge vertex and keep the info. Use this - * only where it is really needed now: like error interrupts. - */ - s = dev_to_name(pcibr_vhdl, devnm, MAXDEVNAME); - pcibr_soft->bs_name = kmalloc(strlen(s) + 1, GFP_KERNEL); - strcpy(pcibr_soft->bs_name, s); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, - "pcibr_attach2: %s ASIC: rev %s (code=0x%x)\n", - "PIC", - (rev == BRIDGE_PART_REV_A) ? "A" : - (rev == BRIDGE_PART_REV_B) ? "B" : - (rev == BRIDGE_PART_REV_C) ? "C" : - (rev == BRIDGE_PART_REV_D) ? "D" : - (rev == XBRIDGE_PART_REV_A) ? "A" : - (rev == XBRIDGE_PART_REV_B) ? "B" : - (IS_PIC_PART_REV_A(rev)) ? "A" : - "unknown", rev, pcibr_soft->bs_name)); - - info = xwidget_info_get(xconn_vhdl); - pcibr_soft->bs_xid = xwidget_info_id_get(info); - pcibr_soft->bs_master = xwidget_info_master_get(info); - pcibr_soft->bs_mxid = xwidget_info_masterid_get(info); - - pcibr_soft->bs_first_slot = pcibr_soft->bs_min_slot; - pcibr_soft->bs_last_slot = pcibr_soft->bs_max_slot; - /* - * Bridge can only reset slots 0, 1, 2, and 3. Ibrick internal - * slots 4, 5, 6, and 7 must be reset as a group, so do not - * reset them. - */ - pcibr_soft->bs_last_reset = 3; - - nasid = NASID_GET(bridge); - - if ((pcibr_soft->bs_bricktype = iobrick_type_get_nasid(nasid)) < 0) - printk(KERN_WARNING "0x%p: Unknown bricktype : 0x%x\n", (void *)xconn_vhdl, - (unsigned int)pcibr_soft->bs_bricktype); - - pcibr_soft->bs_moduleid = iomoduleid_get(nasid); - - if (pcibr_soft->bs_bricktype > 0) { - switch (pcibr_soft->bs_bricktype) { - case MODULE_PXBRICK: - case MODULE_IXBRICK: - pcibr_soft->bs_first_slot = 0; - pcibr_soft->bs_last_slot = 1; - pcibr_soft->bs_last_reset = 1; - - /* If Bus 1 has IO9 then there are 4 devices in that bus. Note - * we figure this out from klconfig since the kernel has yet to - * probe - */ - if (pcibr_widget_to_bus(pcibr_vhdl) == 1) { - lboard_t *brd = (lboard_t *)KL_CONFIG_INFO(nasid); - - while (brd) { - if (brd->brd_flags & LOCAL_MASTER_IO6) { - pcibr_soft->bs_last_slot = 3; - pcibr_soft->bs_last_reset = 3; - } - brd = KLCF_NEXT(brd); - } - } - break; - case MODULE_PBRICK: - pcibr_soft->bs_first_slot = 1; - pcibr_soft->bs_last_slot = 2; - pcibr_soft->bs_last_reset = 2; - break; - - case MODULE_IBRICK: - /* - * Here's the current baseio layout for SN1 style systems: - * - * 0 1 2 3 4 5 6 7 slot# - * - * x scsi x x ioc3 usb x x O300 Ibrick - * - * x == never occupied - * E == external (add-in) slot - * - */ - pcibr_soft->bs_first_slot = 1; /* Ibrick first slot == 1 */ - if (pcibr_soft->bs_xid == 0xe) { - pcibr_soft->bs_last_slot = 2; - pcibr_soft->bs_last_reset = 2; - } else { - pcibr_soft->bs_last_slot = 6; - } - break; - default: - break; - } - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, - "pcibr_attach2: %cbrick, slots %d-%d\n", - MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid), - pcibr_soft->bs_first_slot, pcibr_soft->bs_last_slot)); - } - - /* - * Initialize bridge and bus locks - */ - spin_lock_init(&pcibr_soft->bs_lock); - /* - * If we have one, process the hints structure. - */ - if (pcibr_hints) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, pcibr_vhdl, - "pcibr_attach2: pcibr_hints=0x%x\n", pcibr_hints)); - - rrb_fixed = pcibr_hints->ph_rrb_fixed; - - pcibr_soft->bs_rrb_fixed = rrb_fixed; - - if (pcibr_hints->ph_intr_bits) { - pcibr_soft->bs_intr_bits = pcibr_hints->ph_intr_bits; - } - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - int hslot = pcibr_hints->ph_host_slot[slot] - 1; - - if (hslot < 0) { - pcibr_soft->bs_slot[slot].host_slot = slot; - } else { - pcibr_soft->bs_slot[slot].has_host = 1; - pcibr_soft->bs_slot[slot].host_slot = hslot; - } - } - } - /* - * Set-up initial values for state fields - */ - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE; - pcibr_soft->bs_slot[slot].bss_devio.bssd_ref_cnt = 0; - pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET; - pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET; - pcibr_soft->bs_slot[slot].bss_ext_ates_active = ATOMIC_INIT(0); - pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0] = -1; - } - - for (ibit = 0; ibit < 8; ++ibit) { - pcibr_soft->bs_intr[ibit].bsi_xtalk_intr = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_soft = pcibr_soft; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_stat = - &(bridge->b_int_status); - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_ibit = ibit; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0; - } - - /* - * connect up our error handler. PIC has 2 busses (thus resulting in 2 - * pcibr_soft structs under 1 widget), so only register a xwidget error - * handler for PIC's bus0. NOTE: for PIC pcibr_error_handler_wrapper() - * is a wrapper routine we register that will call the real error handler - * pcibr_error_handler() with the correct pcibr_soft struct. - */ - if (busnum == 0) { - xwidget_error_register(xconn_vhdl, pcibr_error_handler_wrapper, pcibr_soft); - } - - /* - * Initialize various Bridge registers. - */ - - /* - * On pre-Rev.D bridges, set the PCI_RETRY_CNT - * to zero to avoid dropping stores. (#475347) - */ - if (rev < BRIDGE_PART_REV_D) - bridge->b_bus_timeout &= ~BRIDGE_BUS_PCI_RETRY_MASK; - - /* - * Clear all pending interrupts. - */ - bridge->b_int_rst_stat = (BRIDGE_IRR_ALL_CLR); - - /* Initialize some PIC specific registers. */ - { - picreg_t pic_ctrl_reg = bridge->p_wid_control_64; - - /* Bridges Requester ID: bus = busnum, dev = 0, func = 0 */ - pic_ctrl_reg &= ~PIC_CTRL_BUS_NUM_MASK; - pic_ctrl_reg |= PIC_CTRL_BUS_NUM(busnum); - pic_ctrl_reg &= ~PIC_CTRL_DEV_NUM_MASK; - pic_ctrl_reg &= ~PIC_CTRL_FUN_NUM_MASK; - - pic_ctrl_reg &= ~PIC_CTRL_NO_SNOOP; - pic_ctrl_reg &= ~PIC_CTRL_RELAX_ORDER; - - /* enable parity checking on PICs internal RAM */ - pic_ctrl_reg |= PIC_CTRL_PAR_EN_RESP; - pic_ctrl_reg |= PIC_CTRL_PAR_EN_ATE; - /* PIC BRINGUP WAR (PV# 862253): dont enable write request - * parity checking. - */ - if (!PCIBR_WAR_ENABLED(PV862253, pcibr_soft)) { - pic_ctrl_reg |= PIC_CTRL_PAR_EN_REQ; - } - - bridge->p_wid_control_64 = pic_ctrl_reg; - } - bridge->b_int_device = (uint32_t) 0x006db6db; - { - bridgereg_t dirmap; - paddr_t paddr; - iopaddr_t xbase; - xwidgetnum_t xport; - iopaddr_t offset; - int num_entries = 0; - int entry; - cnodeid_t cnodeid; - nasid_t nasid; - - /* Set the Bridge's 32-bit PCI to XTalk - * Direct Map register to the most useful - * value we can determine. Note that we - * must use a single xid for all of: - * direct-mapped 32-bit DMA accesses - * direct-mapped 64-bit DMA accesses - * DMA accesses through the PMU - * interrupts - * This is the only way to guarantee that - * completion interrupts will reach a CPU - * after all DMA data has reached memory. - * (Of course, there may be a few special - * drivers/controlers that explicitly manage - * this ordering problem.) - */ - - cnodeid = 0; /* default node id */ - nasid = COMPACT_TO_NASID_NODEID(cnodeid); - paddr = NODE_OFFSET(nasid) + 0; - - /* currently, we just assume that if we ask - * for a DMA mapping to "zero" the XIO - * host will transmute this into a request - * for the lowest hunk of memory. - */ - xbase = xtalk_dmatrans_addr(xconn_vhdl, 0, - paddr, PAGE_SIZE, 0); - - if (xbase != XIO_NOWHERE) { - if (XIO_PACKED(xbase)) { - xport = XIO_PORT(xbase); - xbase = XIO_ADDR(xbase); - } else - xport = pcibr_soft->bs_mxid; - - offset = xbase & ((1ull << BRIDGE_DIRMAP_OFF_ADDRSHFT) - 1ull); - xbase >>= BRIDGE_DIRMAP_OFF_ADDRSHFT; - - dirmap = xport << BRIDGE_DIRMAP_W_ID_SHFT; - - if (xbase) - dirmap |= BRIDGE_DIRMAP_OFF & xbase; - else if (offset >= (512 << 20)) - dirmap |= BRIDGE_DIRMAP_ADD512; - - bridge->b_dir_map = dirmap; - } - /* - * Set bridge's idea of page size according to the system's - * idea of "IO page size". TBD: The idea of IO page size - * should really go away. - */ - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ -#if IOPGSIZE == 4096 - bridge->p_wid_control_64 &= ~BRIDGE_CTRL_PAGE_SIZE; -#elif IOPGSIZE == 16384 - bridge->p_wid_control_64 |= BRIDGE_CTRL_PAGE_SIZE; -#else - <<>>; -#endif - bridge->b_wid_control; /* inval addr bug war */ - - /* Initialize internal mapping entries */ - for (entry = 0; entry < pcibr_soft->bs_int_ate_size; entry++) { - bridge->b_int_ate_ram[entry].wr = 0; - } - - /* - * Determine if there's external mapping SSRAM on this - * bridge. Set up Bridge control register appropriately, - * inititlize SSRAM, and set software up to manage RAM - * entries as an allocatable resource. - * - * Currently, we just use the rm* routines to manage ATE - * allocation. We should probably replace this with a - * Best Fit allocator. - * - * For now, if we have external SSRAM, avoid using - * the internal ssram: we can't turn PREFETCH on - * when we use the internal SSRAM; and besides, - * this also guarantees that no allocation will - * straddle the internal/external line, so we - * can increment ATE write addresses rather than - * recomparing against BRIDGE_INTERNAL_ATES every - * time. - */ - - num_entries = 0; - - /* we always have 128 ATEs (512 for Xbridge) inside the chip - * even if disabled for debugging. - */ - pcibr_soft->bs_int_ate_resource.start = 0; - pcibr_soft->bs_int_ate_resource.end = pcibr_soft->bs_int_ate_size - 1; - - if (num_entries > pcibr_soft->bs_int_ate_size) { -#if PCIBR_ATE_NOTBOTH /* for debug -- forces us to use external ates */ - printk("pcibr_attach: disabling internal ATEs.\n"); - pcibr_ate_alloc(pcibr_soft, pcibr_soft->bs_int_ate_size); -#endif - pcibr_soft->bs_ext_ate_resource.start = pcibr_soft->bs_int_ate_size; - pcibr_soft->bs_ext_ate_resource.end = num_entries; - } - - pcibr_soft->bs_allocated_ate_res = (void *) kmalloc(pcibr_soft->bs_int_ate_size * sizeof(unsigned long), GFP_KERNEL); - memset(pcibr_soft->bs_allocated_ate_res, 0x0, pcibr_soft->bs_int_ate_size * sizeof(unsigned long)); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, pcibr_vhdl, - "pcibr_attach2: %d ATEs, %d internal & %d external\n", - num_entries ? num_entries : pcibr_soft->bs_int_ate_size, - pcibr_soft->bs_int_ate_size, - num_entries ? num_entries-pcibr_soft->bs_int_ate_size : 0)); - } - - { - bridgereg_t dirmap; - iopaddr_t xbase; - - /* - * now figure the *real* xtalk base address - * that dirmap sends us to. - */ - dirmap = bridge->b_dir_map; - if (dirmap & BRIDGE_DIRMAP_OFF) - xbase = (iopaddr_t)(dirmap & BRIDGE_DIRMAP_OFF) - << BRIDGE_DIRMAP_OFF_ADDRSHFT; - else if (dirmap & BRIDGE_DIRMAP_ADD512) - xbase = 512 << 20; - else - xbase = 0; - - pcibr_soft->bs_dir_xbase = xbase; - - /* it is entirely possible that we may, at this - * point, have our dirmap pointing somewhere - * other than our "master" port. - */ - pcibr_soft->bs_dir_xport = - (dirmap & BRIDGE_DIRMAP_W_ID) >> BRIDGE_DIRMAP_W_ID_SHFT; - } - - /* pcibr sources an error interrupt; - * figure out where to send it. - * - * If any interrupts are enabled in bridge, - * then the prom set us up and our interrupt - * has already been reconnected in mlreset - * above. - * - * Need to set the D_INTR_ISERR flag - * in the dev_desc used for allocating the - * error interrupt, so our interrupt will - * be properly routed and prioritized. - * - * If our crosstalk provider wants to - * fix widget error interrupts to specific - * destinations, D_INTR_ISERR is how it - * knows to do this. - */ - - xtalk_intr = xtalk_intr_alloc(xconn_vhdl, (device_desc_t)0, pcibr_vhdl); - { - int irq = ((hub_intr_t)xtalk_intr)->i_bit; - int cpu = ((hub_intr_t)xtalk_intr)->i_cpuid; - - intr_unreserve_level(cpu, irq); - ((hub_intr_t)xtalk_intr)->i_bit = SGI_PCIBR_ERROR; - } - ASSERT(xtalk_intr != NULL); - - pcibr_soft->bsi_err_intr = xtalk_intr; - - /* - * On IP35 with XBridge, we do some extra checks in pcibr_setwidint - * in order to work around some addressing limitations. In order - * for that fire wall to work properly, we need to make sure we - * start from a known clean state. - */ - pcibr_clearwidint(bridge); - - xtalk_intr_connect(xtalk_intr, (intr_func_t) pcibr_error_intr_handler, - (intr_arg_t) pcibr_soft, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge); - - request_irq(SGI_PCIBR_ERROR, (void *)pcibr_error_intr_handler, SA_SHIRQ, "PCIBR error", - (intr_arg_t) pcibr_soft); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_vhdl, - "pcibr_setwidint: b_wid_int_upper=0x%x, b_wid_int_lower=0x%x\n", - bridge->b_wid_int_upper, bridge->b_wid_int_lower)); - - /* - * now we can start handling error interrupts; - * enable all of them. - * NOTE: some PCI ints may already be enabled. - */ - int_enable_64 = bridge->p_int_enable_64 | BRIDGE_ISR_ERRORS; - int_enable = (uint64_t)int_enable_64; - -#if BRIDGE_ERROR_INTR_WAR - if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) { - /* - * We commonly get master timeouts when talking to ql. - * We also see RESP_XTALK_ERROR and LLP_TX_RETRY interrupts. - * Insure that these are all disabled for now. - */ - int_enable &= ~(BRIDGE_IMR_PCI_MST_TIMEOUT | - BRIDGE_ISR_RESP_XTLK_ERR | - BRIDGE_ISR_LLP_TX_RETRY); - } - if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_C) { - int_enable &= ~BRIDGE_ISR_BAD_XRESP_PKT; - } -#endif /* BRIDGE_ERROR_INTR_WAR */ - -#ifdef QL_SCSI_CTRL_WAR /* for IP30 only */ - /* Really a QL rev A issue, but all newer hearts have newer QLs. - * Forces all IO6/MSCSI to be new. - */ - if (heart_rev() == HEART_REV_A) - int_enable &= ~BRIDGE_IMR_PCI_MST_TIMEOUT; -#endif - -#ifdef BRIDGE1_TIMEOUT_WAR - if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) { - /* - * Turn off these interrupts. They can't be trusted in bridge 1 - */ - int_enable &= ~(BRIDGE_IMR_XREAD_REQ_TIMEOUT | - BRIDGE_IMR_UNEXP_RESP); - } -#endif - - /* PIC BRINGUP WAR (PV# 856864 & 856865): allow the tnums that are - * locked out to be freed up sooner (by timing out) so that the - * read tnums are never completely used up. - */ - if (PCIBR_WAR_ENABLED(PV856864, pcibr_soft)) { - int_enable &= ~PIC_ISR_PCIX_REQ_TOUT; - int_enable &= ~BRIDGE_ISR_XREAD_REQ_TIMEOUT; - - bridge->b_wid_req_timeout = 0x750; - } - - /* - * PIC BRINGUP WAR (PV# 856866, 859504, 861476, 861478): Don't use - * RRB0, RRB8, RRB1, and RRB9. Assign them to DEVICE[2|3]--VCHAN3 - * so they are not used - */ - if (PCIBR_WAR_ENABLED(PV856866, pcibr_soft)) { - bridge->b_even_resp |= 0x000f000f; - bridge->b_odd_resp |= 0x000f000f; - } - - bridge->p_int_enable_64 = (picreg_t)int_enable; - bridge->b_int_mode = 0; /* do not send "clear interrupt" packets */ - - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - - /* - * Depending on the rev of bridge, disable certain features. - * Easiest way seems to be to force the PCIBR_NOwhatever - * flag to be on for all DMA calls, which overrides any - * PCIBR_whatever flag or even the setting of whatever - * from the PCIIO_DMA_class flags (or even from the other - * PCIBR flags, since NO overrides YES). - */ - pcibr_soft->bs_dma_flags = 0; - - /* PREFETCH: - * Always completely disabled for REV.A; - * at "pcibr_prefetch_enable_rev", anyone - * asking for PCIIO_PREFETCH gets it. - * Between these two points, you have to ask - * for PCIBR_PREFETCH, which promises that - * your driver knows about known Bridge WARs. - */ - if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_B) - pcibr_soft->bs_dma_flags |= PCIBR_NOPREFETCH; - else if (pcibr_soft->bs_rev_num < - (BRIDGE_WIDGET_PART_NUM << 4)) - pcibr_soft->bs_dma_flags |= PCIIO_NOPREFETCH; - - /* WRITE_GATHER: Disabled */ - if (pcibr_soft->bs_rev_num < - (BRIDGE_WIDGET_PART_NUM << 4)) - pcibr_soft->bs_dma_flags |= PCIBR_NOWRITE_GATHER; - - /* PIC only supports 64-bit direct mapping in PCI-X mode. Since - * all PCI-X devices that initiate memory transactions must be - * capable of generating 64-bit addressed, we force 64-bit DMAs. - */ - if (IS_PCIX(pcibr_soft)) { - pcibr_soft->bs_dma_flags |= PCIIO_DMA_A64; - } - - { - - iopaddr_t prom_base_addr = pcibr_soft->bs_xid << 24; - int prom_base_size = 0x1000000; - int status; - struct resource *res; - - /* Allocate resource maps based on bus page size; for I/O and memory - * space, free all pages except those in the base area and in the - * range set by the PROM. - * - * PROM creates BAR addresses in this format: 0x0ws00000 where w is - * the widget number and s is the device register offset for the slot. - */ - - /* Setup the Bus's PCI IO Root Resource. */ - pcibr_soft->bs_io_win_root_resource.start = PCIBR_BUS_IO_BASE; - pcibr_soft->bs_io_win_root_resource.end = 0xffffffff; - res = (struct resource *) kmalloc( sizeof(struct resource), GFP_KERNEL); - if (!res) - panic("PCIBR:Unable to allocate resource structure\n"); - - /* Block off the range used by PROM. */ - res->start = prom_base_addr; - res->end = prom_base_addr + (prom_base_size - 1); - status = request_resource(&pcibr_soft->bs_io_win_root_resource, res); - if (status) - panic("PCIBR:Unable to request_resource()\n"); - - /* Setup the Small Window Root Resource */ - pcibr_soft->bs_swin_root_resource.start = PAGE_SIZE; - pcibr_soft->bs_swin_root_resource.end = 0x000FFFFF; - - /* Setup the Bus's PCI Memory Root Resource */ - pcibr_soft->bs_mem_win_root_resource.start = 0x200000; - pcibr_soft->bs_mem_win_root_resource.end = 0xffffffff; - res = (struct resource *) kmalloc( sizeof(struct resource), GFP_KERNEL); - if (!res) - panic("PCIBR:Unable to allocate resource structure\n"); - - /* Block off the range used by PROM. */ - res->start = prom_base_addr; - res->end = prom_base_addr + (prom_base_size - 1);; - status = request_resource(&pcibr_soft->bs_mem_win_root_resource, res); - if (status) - panic("PCIBR:Unable to request_resource()\n"); - - } - - /* build "no-slot" connection point - */ - pcibr_info = pcibr_device_info_new - (pcibr_soft, PCIIO_SLOT_NONE, PCIIO_FUNC_NONE, - PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); - noslot_conn = pciio_device_info_register - (pcibr_vhdl, &pcibr_info->f_c); - - /* Remember the no slot connection point info for tearing it - * down during detach. - */ - pcibr_soft->bs_noslot_conn = noslot_conn; - pcibr_soft->bs_noslot_info = pcibr_info; -#if PCI_FBBE - fast_back_to_back_enable = 1; -#endif - -#if PCI_FBBE - if (fast_back_to_back_enable) { - /* - * All devices on the bus are capable of fast back to back, so - * we need to set the fast back to back bit in all devices on - * the bus that are capable of doing such accesses. - */ - } -#endif - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - /* Find out what is out there */ - (void)pcibr_slot_info_init(pcibr_vhdl,slot); - } - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) - /* Set up the address space for this slot in the PCI land */ - (void)pcibr_slot_addr_space_init(pcibr_vhdl, slot); - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) - /* Setup the device register */ - (void)pcibr_slot_device_init(pcibr_vhdl, slot); - - if (IS_PCIX(pcibr_soft)) { - pcibr_soft->bs_pcix_rbar_inuse = 0; - pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR; - pcibr_soft->bs_pcix_rbar_percent_allowed = - pcibr_pcix_rbars_calc(pcibr_soft); - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) - /* Setup the PCI-X Read Buffer Attribute Registers (RBARs) */ - (void)pcibr_slot_pcix_rbar_init(pcibr_soft, slot); - } - - /* Set up convenience links */ - pcibr_bus_cnvlink(pcibr_soft->bs_vhdl); - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) - /* Setup host/guest relations */ - (void)pcibr_slot_guest_info_init(pcibr_vhdl, slot); - - /* Handle initial RRB management for Bridge and Xbridge */ - pcibr_initial_rrb(pcibr_vhdl, - pcibr_soft->bs_first_slot, pcibr_soft->bs_last_slot); - -{ /* Before any drivers get called that may want to re-allocate - * RRB's, let's get some special cases pre-allocated. Drivers - * may override these pre-allocations, but by doing pre-allocations - * now we're assured not to step all over what the driver intended. - * - * Note: Someday this should probably be moved over to pcibr_rrb.c - */ - /* - * Each Pbrick PCI bus only has slots 1 and 2. Similarly for - * widget 0xe on Ibricks. Allocate RRB's accordingly. - */ - if (pcibr_soft->bs_bricktype > 0) { - switch (pcibr_soft->bs_bricktype) { - case MODULE_PBRICK: - do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8); - break; - case MODULE_IBRICK: - /* port 0xe on the Ibrick only has slots 1 and 2 */ - if (pcibr_soft->bs_xid == 0xe) { - do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8); - } - else { - /* allocate one RRB for the serial port */ - do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 1); - } - break; - case MODULE_PXBRICK: - case MODULE_IXBRICK: - /* - * If the IO9 is in the PXBrick (bus1, slot1) allocate - * RRBs to all the devices - */ - if ((pcibr_widget_to_bus(pcibr_vhdl) == 1) && - (pcibr_soft->bs_slot[0].bss_vendor_id == 0x10A9) && - (pcibr_soft->bs_slot[0].bss_device_id == 0x100A)) { - do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 4); - do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 4); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 4); - do_pcibr_rrb_autoalloc(pcibr_soft, 3, VCHAN0, 4); - } else { - do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); - } - break; - } /* switch */ - } - -#ifdef LATER - if (strstr(nicinfo, XTALK_PCI_PART_NUM)) { - do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); - } -#endif -} /* OK Special RRB allocations are done. */ - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) - /* Call the device attach */ - (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); - - pciio_device_attach(noslot_conn, (int)0); - - return 0; -} - /* * pcibr_detach: * Detach the bridge device from the hwgraph after cleaning out all the @@ -1777,25 +686,22 @@ int pcibr_detach(vertex_hdl_t xconn) { - pciio_slot_t slot; - vertex_hdl_t pcibr_vhdl; - pcibr_soft_t pcibr_soft; - bridge_t *bridge; - unsigned s; + pciio_slot_t slot; + vertex_hdl_t pcibr_vhdl; + pcibr_soft_t pcibr_soft; + unsigned long s; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DETACH, xconn, "pcibr_detach\n")); /* Get the bridge vertex from its xtalk connection point */ if (hwgraph_traverse(xconn, EDGE_LBL_PCI, &pcibr_vhdl) != GRAPH_SUCCESS) - return(1); + return 1; pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge = pcibr_soft->bs_base; - - s = pcibr_lock(pcibr_soft); /* Disable the interrupts from the bridge */ - bridge->p_int_enable_64 = 0; + s = pcibr_lock(pcibr_soft); + pcireg_intr_enable_set(pcibr_soft, 0); pcibr_unlock(pcibr_soft, s); /* Detach all the PCI devices talking to this bridge */ @@ -1823,26 +729,64 @@ /* Remove the Bridge revision labelled info */ (void)hwgraph_info_remove_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, NULL); - /* Remove the character device associated with this bridge */ - hwgraph_edge_remove(pcibr_vhdl, EDGE_LBL_CONTROLLER, NULL); - /* Remove the PCI bridge vertex */ - hwgraph_edge_remove(xconn, EDGE_LBL_PCI, NULL); - return(0); + return 0; } + +/* + * Set the Bridge's 32-bit PCI to XTalk Direct Map register to the most useful + * value we can determine. Note that we must use a single xid for all of: + * -direct-mapped 32-bit DMA accesses + * -direct-mapped 64-bit DMA accesses + * -DMA accesses through the PMU + * -interrupts + * This is the only way to guarantee that completion interrupts will reach a + * CPU after all DMA data has reached memory. + */ +void +pcibr_directmap_init(pcibr_soft_t pcibr_soft) +{ + paddr_t paddr; + iopaddr_t xbase; + uint64_t diroff; + cnodeid_t cnodeid = 0; /* We need api for diroff api */ + nasid_t nasid; + + nasid = COMPACT_TO_NASID_NODEID(cnodeid); + paddr = NODE_OFFSET(nasid) + 0; + + /* Assume that if we ask for a DMA mapping to zero the XIO host will + * transmute this into a request for the lowest hunk of memory. + */ + xbase = xtalk_dmatrans_addr(pcibr_soft->bs_conn, 0, paddr, PAGE_SIZE, 0); + + diroff = xbase >> BRIDGE_DIRMAP_OFF_ADDRSHFT; + pcireg_dirmap_diroff_set(pcibr_soft, diroff); + pcireg_dirmap_wid_set(pcibr_soft, pcibr_soft->bs_mxid); + pcibr_soft->bs_dir_xport = pcibr_soft->bs_mxid; + if (xbase == (512 << 20)) { /* 512Meg */ + pcireg_dirmap_add512_set(pcibr_soft); + pcibr_soft->bs_dir_xbase = (512 << 20); + } else { + pcireg_dirmap_add512_clr(pcibr_soft); + pcibr_soft->bs_dir_xbase = diroff << BRIDGE_DIRMAP_OFF_ADDRSHFT; + } +} + + int pcibr_asic_rev(vertex_hdl_t pconn_vhdl) { - vertex_hdl_t pcibr_vhdl; - int tmp_vhdl; + vertex_hdl_t pcibr_vhdl; + int rc; arbitrary_info_t ainfo; if (GRAPH_SUCCESS != hwgraph_traverse(pconn_vhdl, EDGE_LBL_MASTER, &pcibr_vhdl)) return -1; - tmp_vhdl = hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo); + rc = hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo); /* * Any hwgraph function that returns a vertex handle will implicity @@ -1855,20 +799,10 @@ */ hwgraph_vertex_unref(pcibr_vhdl); - if (tmp_vhdl != GRAPH_SUCCESS) + if (rc != GRAPH_SUCCESS) return -1; - return (int) ainfo; -} -int -pcibr_write_gather_flush(vertex_hdl_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - pciio_slot_t slot; - slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - pcibr_device_write_gather_flush(pcibr_soft, slot); - return 0; + return (int) ainfo; } /* ===================================================================== @@ -1884,14 +818,12 @@ unsigned flags) { pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_info_t pciio_info = &pcibr_info->f_c; + pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - unsigned bar; /* which BASE reg on device is decoding */ iopaddr_t xio_addr = XIO_NOWHERE; - iopaddr_t base; /* base of devio(x) mapped area on PCI */ - iopaddr_t limit; /* base of devio(x) mapped area on PCI */ + iopaddr_t base = 0; + iopaddr_t limit = 0; pciio_space_t wspace; /* which space device is decoding */ iopaddr_t wbase; /* base of device decode on PCI */ @@ -2012,7 +944,7 @@ maxtry = PCIBR_NUM_SLOTS(pcibr_soft) * 2; halftry = PCIBR_NUM_SLOTS(pcibr_soft) - 1; for (try = 0; try < maxtry; ++try) { - bridgereg_t devreg; + uint64_t devreg; unsigned offset; /* calculate win based on slot, attempt, and max possible @@ -2080,14 +1012,13 @@ devreg &= ~BRIDGE_DEV_DEV_SWAP; if (pcibr_soft->bs_slot[win].bss_device != devreg) { - bridge->b_device[win].reg = devreg; + pcireg_device_set(pcibr_soft, win, devreg); pcibr_soft->bs_slot[win].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ -#ifdef PCI_LATER + pcireg_tflush_get(pcibr_soft); + PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pconn_vhdl, "pcibr_addr_pci_to_xio: Device(%d): 0x%x\n", win, devreg)); -#endif } pcibr_soft->bs_slot[win].bss_devio.bssd_space = space; pcibr_soft->bs_slot[win].bss_devio.bssd_base = mbase; @@ -2200,7 +1131,7 @@ if (xio_addr != XIO_NOWHERE) { unsigned bst; /* nonzero to set bytestream */ unsigned *bfp; /* addr of record of how swapper is set */ - unsigned swb; /* which control bit to mung */ + uint64_t swb; /* which control bit to mung */ unsigned bfo; /* current swapper setting */ unsigned bfn; /* desired swapper setting */ @@ -2226,13 +1157,13 @@ bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : "")); xio_addr = XIO_NOWHERE; } else { /* OK to make the change. */ - picreg_t octl, nctl; - swb = (space == PCIIO_SPACE_IO) ? BRIDGE_CTRL_IO_SWAP : BRIDGE_CTRL_MEM_SWAP; - octl = bridge->p_wid_control_64; - nctl = bst ? octl | (uint64_t)swb : octl & ((uint64_t)~swb); + swb = (space == PCIIO_SPACE_IO) ? 0: BRIDGE_CTRL_MEM_SWAP; + if (bst) { + pcireg_control_bit_set(pcibr_soft, swb); + } else { + pcireg_control_bit_clr(pcibr_soft, swb); + } - if (octl != nctl) /* make the change if any */ - bridge->b_wid_control = nctl; *bfp = bfn; /* record the assignment */ PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, @@ -2324,7 +1255,7 @@ pcibr_piomap->bp_pciaddr = pci_addr; pcibr_piomap->bp_mapsz = req_size; pcibr_piomap->bp_soft = pcibr_soft; - pcibr_piomap->bp_toc[0] = ATOMIC_INIT(0); + pcibr_piomap->bp_toc = ATOMIC_INIT(0); if (mapptr) { s = pcibr_lock(pcibr_soft); @@ -2383,7 +1314,7 @@ "pcibr_piomap_addr: map=0x%lx, addr=0x%lx\n", pcibr_piomap, addr)); - return(addr); + return addr; } /*ARGSUSED */ @@ -2424,7 +1355,7 @@ PCIBR_DEBUG((PCIBR_DEBUG_PIODIR, pconn_vhdl, "pcibr_piotrans_addr: xio_addr=0x%lx, addr=0x%lx\n", xio_addr, addr)); - return(addr); + return addr; } /* @@ -2546,6 +1477,7 @@ return start_addr; } +#define ERR_MSG "!Device %s freeing size (0x%lx) different than allocated (0x%lx)" /*ARGSUSED */ void pcibr_piospace_free(vertex_hdl_t pconn_vhdl, @@ -2689,7 +1621,7 @@ attributes &= (PCI64_ATTR_BAR | PCI64_ATTR_SWAP); } - return (attributes); + return attributes; } /*ARGSUSED */ @@ -2775,7 +1707,7 @@ else min_rrbs = 1; if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, slot, vchan, + pcibr_rrb_alloc_more(pcibr_soft, slot, vchan, min_rrbs - have_rrbs); } } @@ -2845,7 +1777,7 @@ - 1) + 1; /* round UP */ } - ate_index = pcibr_ate_alloc(pcibr_soft, ate_count); + ate_index = pcibr_ate_alloc(pcibr_soft, ate_count, &pcibr_dmamap->resource); if (ate_index != -1) { if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_PMU_BITS)) { @@ -2857,7 +1789,7 @@ "pcibr_dmamap_alloc: using PMU, ate_index=%d, " "pcibr_dmamap=0x%lx\n", ate_index, pcibr_dmamap)); - ate_proto = pcibr_flags_to_ate(flags); + ate_proto = pcibr_flags_to_ate(pcibr_soft, flags); pcibr_dmamap->bd_flags = flags; pcibr_dmamap->bd_pci_addr = @@ -2890,7 +1822,7 @@ else min_rrbs = 1; if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, slot, vchan, + pcibr_rrb_alloc_more(pcibr_soft, slot, vchan, min_rrbs - have_rrbs); } } @@ -2900,7 +1832,7 @@ "pcibr_dmamap_alloc: PMU use failed, ate_index=%d\n", ate_index)); - pcibr_ate_free(pcibr_soft, ate_index, ate_count); + pcibr_ate_free(pcibr_soft, ate_index, ate_count, &pcibr_dmamap->resource); } /* total failure: sorry, you just can't * get from here to there that way. @@ -2920,16 +1852,6 @@ pciio_slot_t slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, pcibr_dmamap->bd_slot); - unsigned flags = pcibr_dmamap->bd_flags; - - /* Make sure that bss_ext_ates_active - * is properly kept up to date. - */ - - if (PCIBR_DMAMAP_BUSY & flags) - if (PCIBR_DMAMAP_SSRAM & flags) - atomic_dec(&(pcibr_soft->bs_slot[slot]. bss_ext_ates_active)); - xtalk_dmamap_free(pcibr_dmamap->bd_xtalk); if (pcibr_dmamap->bd_flags & PCIIO_DMA_A64) { @@ -2938,8 +1860,9 @@ if (pcibr_dmamap->bd_ate_count) { pcibr_ate_free(pcibr_dmamap->bd_soft, pcibr_dmamap->bd_ate_index, - pcibr_dmamap->bd_ate_count); - pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_PMU_BITS); + pcibr_dmamap->bd_ate_count, + &pcibr_dmamap->resource); + pcibr_release_device(pcibr_soft, slot, XBRIDGE_DEV_PMU_BITS); } PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, @@ -2992,7 +1915,7 @@ for (slot = soft->bs_min_slot; slot < PCIBR_NUM_SLOTS(soft); ++slot) if ((xio_addr >= PCIBR_BRIDGE_DEVIO(soft, slot)) && (xio_lim < PCIBR_BRIDGE_DEVIO(soft, slot + 1))) { - bridgereg_t dev; + uint64_t dev; dev = soft->bs_slot[slot].bss_device; pci_addr = dev & BRIDGE_DEV_OFF_MASK; @@ -3091,33 +2014,14 @@ paddr, paddr + req_size - 1, xio_port, xio_addr, pci_addr)); } else { - bridge_t *bridge = pcibr_soft->bs_base; iopaddr_t offset = IOPGOFF(xio_addr); bridge_ate_t ate_proto = pcibr_dmamap->bd_ate_proto; int ate_count = IOPG(offset + req_size - 1) + 1; - int ate_index = pcibr_dmamap->bd_ate_index; - unsigned cmd_regs[8]; - unsigned s; - -#if PCIBR_FREEZE_TIME - int ate_total = ate_count; - unsigned freeze_time; -#endif - bridge_ate_p ate_ptr = pcibr_dmamap->bd_ate_ptr; bridge_ate_t ate; - /* Bridge Hardware WAR #482836: - * If the transfer is not cache aligned - * and the Bridge Rev is <= B, force - * prefetch to be off. - */ - if (flags & PCIBR_NOPREFETCH) - ate_proto &= ~ATE_PREF; - - ate = ate_proto - | (xio_port << ATE_TIDSHIFT) - | (xio_addr - offset); + ate = ate_proto | (xio_addr - offset); + ate |= (xio_port << ATE_TIDSHIFT); pci_addr = pcibr_dmamap->bd_pci_addr + offset; @@ -3128,10 +2032,8 @@ ASSERT(ate_count > 0); if (ate_count <= pcibr_dmamap->bd_ate_count) { - ATE_FREEZE(); - ATE_WRITE(); - ATE_THAW(); - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + ate_write(pcibr_soft, ate_index, ate_count, ate); + PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, "pcibr_dmamap_addr (PMU) : wanted paddr " "[0x%lx..0x%lx] returning PCI 0x%lx\n", @@ -3163,19 +2065,6 @@ void pcibr_dmamap_done(pcibr_dmamap_t pcibr_dmamap) { - /* - * We could go through and invalidate ATEs here; - * for performance reasons, we don't. - * We also don't enforce the strict alternation - * between _addr/_list and _done, but Hub does. - */ - - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { - pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; - - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) - atomic_dec(&(pcibr_dmamap->bd_soft->bs_slot[pcibr_dmamap->bd_slot]. bss_ext_ates_active)); - } xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, @@ -3198,7 +2087,7 @@ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - return(NASID_TO_COMPACT_NODEID(NASID_GET(pcibr_soft->bs_dir_xbase))); + return NASID_TO_COMPACT_NODEID(NASID_GET(pcibr_soft->bs_dir_xbase)); } /*ARGSUSED */ @@ -3281,17 +2170,13 @@ if ((pci_addr != PCIBR_D64_BASE_UNSET) && (flags == slotp->bss_d64_flags)) { - pci_addr |= xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - -#if HWG_PERF_CHECK - if (xio_addr != 0x20000000) -#endif - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], " - "xio_port=0x%x, direct64: pci_addr=0x%x\n", - paddr, paddr + req_size - 1, xio_addr, pci_addr)); - return (pci_addr); + pci_addr |= xio_addr | + ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); + PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, + "pcibr_dmatrans_addr: wanted paddr [0x%lx..0x%lx], " + "xio_port=0x%x, direct64: pci_addr=0x%lx\n", + paddr, paddr + req_size - 1, xio_addr, pci_addr)); + return pci_addr; } if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS)) { pci_addr = pcibr_flags_to_d64(flags, pcibr_soft); @@ -3313,7 +2198,7 @@ else min_rrbs = 1; if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, vchan, + pcibr_rrb_alloc_more(pcibr_soft, pciio_slot, vchan, min_rrbs - have_rrbs); } } @@ -3322,7 +2207,7 @@ "xio_port=0x%x, direct64: pci_addr=0x%lx, " "new flags: 0x%x\n", paddr, paddr + req_size - 1, xio_addr, pci_addr, (uint64_t) flags)); - return (pci_addr); + return pci_addr; } PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, @@ -3375,7 +2260,7 @@ " xio_port=0x%x, direct32: pci_addr=0x%lx\n", paddr, paddr + req_size - 1, xio_addr, pci_addr)); - return (pci_addr); + return pci_addr; } if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS)) { @@ -3394,7 +2279,7 @@ else min_rrbs = 1; if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, + pcibr_rrb_alloc_more(pcibr_soft, pciio_slot, vchan, min_rrbs - have_rrbs); } } @@ -3404,7 +2289,7 @@ "new flags: 0x%x\n", paddr, paddr + req_size - 1, xio_addr, pci_addr, (uint64_t) flags)); - return (pci_addr); + return pci_addr; } /* our flags conflict with Device(x). */ @@ -3441,17 +2326,6 @@ xtalk_dmaaddr_drain(xconn_vhdl, paddr, bytes); } -void -pcibr_dmalist_drain(vertex_hdl_t pconn_vhdl, - alenlist_t list) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; - - xtalk_dmalist_drain(xconn_vhdl, list); -} - /* * Get the starting PCIbus address out of the given DMA map. * This function is supposed to be used by a close friend of PCI bridge @@ -3461,7 +2335,7 @@ iopaddr_t pcibr_dmamap_pciaddr_get(pcibr_dmamap_t pcibr_dmamap) { - return (pcibr_dmamap->bd_pci_addr); + return pcibr_dmamap->bd_pci_addr; } /* ===================================================================== @@ -3494,8 +2368,8 @@ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridgereg_t devreg; - unsigned long s; + uint64_t devreg; + unsigned long s; /* * Bridge supports hardware swapping; so we can always @@ -3514,102 +2388,17 @@ * have to change the logic here. */ if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { - bridge_t *bridge = pcibr_soft->bs_base; - - bridge->b_device[pciio_slot].reg = devreg; - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - pcibr_unlock(pcibr_soft, s); - - printk("pcibr_endian_set: Device(%d): %x\n", pciio_slot, devreg); - return desired_end; -} - -/* This (re)sets the GBR and REALTIME bits and also keeps track of how - * many sets are outstanding. Reset succeeds only if the number of outstanding - * sets == 1. - */ -int -pcibr_priority_bits_set(pcibr_soft_t pcibr_soft, - pciio_slot_t pciio_slot, - pciio_priority_t device_prio) -{ - unsigned long s; - int *counter; - bridgereg_t rtbits = 0; - bridgereg_t devreg; - int rc = PRIO_SUCCESS; - - /* in dual-slot configurations, the host and the - * guest have separate DMA resources, so they - * have separate requirements for priority bits. - */ - - counter = &(pcibr_soft->bs_slot[pciio_slot].bss_pri_uctr); - - /* - * Bridge supports PCI notions of LOW and HIGH priority - * arbitration rings via a "REAL_TIME" bit in the per-device - * Bridge register. The "GBR" bit controls access to the GBR - * ring on the xbow. These two bits are (re)set together. - * - * XXX- Bug in Rev B Bridge Si: - * Symptom: Prefetcher starts operating incorrectly. This happens - * due to corruption of the address storage ram in the prefetcher - * when a non-real time PCI request is pulled and a real-time one is - * put in it's place. Workaround: Use only a single arbitration ring - * on PCI bus. GBR and RR can still be uniquely used per - * device. NETLIST MERGE DONE, WILL BE FIXED IN REV C. - */ - - if (pcibr_soft->bs_rev_num != BRIDGE_PART_REV_B) - rtbits |= BRIDGE_DEV_RT; - - /* NOTE- if we ever put DEV_RT or DEV_GBR on - * the disabled list, we will have to take - * it into account here. - */ - - s = pcibr_lock(pcibr_soft); - devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; - if (device_prio == PCI_PRIO_HIGH) { - if ((++*counter == 1)) { - if (rtbits) - devreg |= rtbits; - else - rc = PRIO_FAIL; - } - } else if (device_prio == PCI_PRIO_LOW) { - if (*counter <= 0) - rc = PRIO_FAIL; - else if (--*counter == 0) - if (rtbits) - devreg &= ~rtbits; - } - if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { - bridge_t *bridge = pcibr_soft->bs_base; - - bridge->b_device[pciio_slot].reg = devreg; + pcireg_device_set(pcibr_soft, pciio_slot, devreg); pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + pcireg_tflush_get(pcibr_soft); } pcibr_unlock(pcibr_soft, s); - return rc; -} - -pciio_priority_t -pcibr_priority_set(vertex_hdl_t pconn_vhdl, - pciio_priority_t device_prio) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - (void) pcibr_priority_bits_set(pcibr_soft, pciio_slot, device_prio); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pconn_vhdl, + "pcibr_endian_set: Device(%d): 0x%x\n", + pciio_slot, devreg)); - return device_prio; + return desired_end; } /* @@ -3630,8 +2419,8 @@ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridgereg_t set = 0; - bridgereg_t clr = 0; + uint64_t set = 0; + uint64_t clr = 0; ASSERT((flags & PCIBR_DEVICE_FLAGS) == flags); @@ -3640,11 +2429,6 @@ if (flags & PCIBR_NOWRITE_GATHER) clr |= BRIDGE_DEV_PMU_WRGA_EN; - if (flags & PCIBR_WRITE_GATHER) - set |= BRIDGE_DEV_DIR_WRGA_EN; - if (flags & PCIBR_NOWRITE_GATHER) - clr |= BRIDGE_DEV_DIR_WRGA_EN; - if (flags & PCIBR_PREFETCH) set |= BRIDGE_DEV_PREF; if (flags & PCIBR_NOPREFETCH) @@ -3665,19 +2449,22 @@ if (flags & PCIBR_NO64BIT) clr |= BRIDGE_DEV_DEV_SIZE; + /* PIC BRINGUP WAR (PV# 878674): Don't allow 64bit PIO accesses */ + if ((flags & PCIBR_64BIT) && PCIBR_WAR_ENABLED(PV878674, pcibr_soft)) { + set &= ~BRIDGE_DEV_DEV_SIZE; + } + if (set || clr) { - bridgereg_t devreg; - unsigned long s; + uint64_t devreg; + unsigned long s; s = pcibr_lock(pcibr_soft); devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; devreg = (devreg & ~clr) | set; if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { - bridge_t *bridge = pcibr_soft->bs_base; - - bridge->b_device[pciio_slot].reg = devreg; + pcireg_device_set(pcibr_soft, pciio_slot, devreg); pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + pcireg_tflush_get(pcibr_soft); } pcibr_unlock(pcibr_soft, s); @@ -3685,7 +2472,7 @@ "pcibr_device_flags_set: Device(%d): 0x%x\n", pciio_slot, devreg)); } - return (1); + return 1; } /* @@ -3711,7 +2498,7 @@ printk(KERN_WARNING "%lx: Must oversubscribe Read Buffer Attribute Registers" "(RBAR). Bus has %d RBARs but %d funcs need them.\n", - (unsigned long)pcibr_soft->bs_vhdl, NUM_RBAR, pcibr_soft->bs_pcix_num_funcs); + pcibr_soft->bs_name, NUM_RBAR, pcibr_soft->bs_pcix_num_funcs); percent_allowed = 0; } else { percent_allowed = (((NUM_RBAR-pcibr_soft->bs_pcix_num_funcs)*100) / @@ -3728,51 +2515,12 @@ percent_allowed=(percent_allowed > 100) ? 100 : percent_allowed+1; } } else { - return(ENODEV); + return -ENODEV; } - return(percent_allowed); + return percent_allowed; } -pciio_provider_t pcibr_provider = -{ - (pciio_piomap_alloc_f *) pcibr_piomap_alloc, - (pciio_piomap_free_f *) pcibr_piomap_free, - (pciio_piomap_addr_f *) pcibr_piomap_addr, - (pciio_piomap_done_f *) pcibr_piomap_done, - (pciio_piotrans_addr_f *) pcibr_piotrans_addr, - (pciio_piospace_alloc_f *) pcibr_piospace_alloc, - (pciio_piospace_free_f *) pcibr_piospace_free, - - (pciio_dmamap_alloc_f *) pcibr_dmamap_alloc, - (pciio_dmamap_free_f *) pcibr_dmamap_free, - (pciio_dmamap_addr_f *) pcibr_dmamap_addr, - (pciio_dmamap_done_f *) pcibr_dmamap_done, - (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr, - (pciio_dmamap_drain_f *) pcibr_dmamap_drain, - (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain, - (pciio_dmalist_drain_f *) pcibr_dmalist_drain, - - (pciio_intr_alloc_f *) pcibr_intr_alloc, - (pciio_intr_free_f *) pcibr_intr_free, - (pciio_intr_connect_f *) pcibr_intr_connect, - (pciio_intr_disconnect_f *) pcibr_intr_disconnect, - (pciio_intr_cpu_get_f *) pcibr_intr_cpu_get, - - (pciio_provider_startup_f *) pcibr_provider_startup, - (pciio_provider_shutdown_f *) pcibr_provider_shutdown, - (pciio_reset_f *) pcibr_reset, - (pciio_write_gather_flush_f *) pcibr_write_gather_flush, - (pciio_endian_set_f *) pcibr_endian_set, - (pciio_priority_set_f *) pcibr_priority_set, - (pciio_config_get_f *) pcibr_config_get, - (pciio_config_set_f *) pcibr_config_set, - (pciio_error_extract_f *) 0, - (pciio_driver_reg_callback_f *) 0, - (pciio_driver_unreg_callback_f *) 0, - (pciio_device_unregister_f *) pcibr_device_unregister, -}; - /* * pcibr_debug() is used to print pcibr debug messages to the console. A * user enables tracing by setting the following global variables: @@ -3794,6 +2542,7 @@ { char hwpath[MAXDEVNAME] = "\0"; char copy_of_hwpath[MAXDEVNAME]; + char *buffer; char *module = "all"; short widget = -1; short slot = -1; @@ -3836,38 +2585,59 @@ (!strcmp(module, pcibr_debug_module) && (widget == pcibr_debug_widget) && (slot == pcibr_debug_slot))) { -#ifdef LATER - printk("PCIBR_DEBUG<%d>\t: %s :", cpuid(), hwpath); -#else - printk("PCIBR_DEBUG\t: %s :", hwpath); -#endif - /* - * Kernel printk translates to this 3 line sequence. - * Since we have a variable length argument list, we - * need to call printk this way rather than directly - */ - { - char buffer[500]; + buffer = kmalloc(1024, GFP_KERNEL); + if (buffer) { + printk("PCIBR_DEBUG<%d>\t: %s :", smp_processor_id(), hwpath); + /* + * KERN_MSG translates to this 3 line sequence. Since + * we have a variable length argument list, we need to + * call KERN_MSG this way rather than directly + */ va_start(ap, format); - vsnprintf(buffer, 500, format, ap); + memset(buffer, 0, 1024); + vsnprintf(buffer, 1024, format, ap); va_end(ap); - buffer[499] = (char)0; /* just to be safe */ - printk("%s", buffer); + printk("", "%s", buffer); + kfree(buffer); } } } } +/* + * given a xconn_vhdl and a bus number under that widget, return a + * bridge_t pointer. + */ +void * +pcibr_bridge_ptr_get(vertex_hdl_t widget_vhdl, int bus_num) +{ + void *bridge; + + bridge = (void *)xtalk_piotrans_addr(widget_vhdl, 0, 0, + sizeof(bridge), 0); + + /* PIC ASIC has two bridges (ie. two buses) under a single widget */ + if (bus_num == 1) { + bridge = (void *)((char *)bridge + PIC_BUS1_OFFSET); + } + return bridge; +} + + int -isIO9(nasid_t nasid) { +isIO9(nasid_t nasid) +{ lboard_t *brd = (lboard_t *)KL_CONFIG_INFO(nasid); while (brd) { if (brd->brd_flags & LOCAL_MASTER_IO6) { return 1; } - brd = KLCF_NEXT(brd); + if (numionodes == numnodes) + brd = KLCF_NEXT_ANY(brd); + else + brd = KLCF_NEXT(brd); } /* if it's dual ported, check the peer also */ nasid = NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer; @@ -3877,7 +2647,11 @@ if (brd->brd_flags & LOCAL_MASTER_IO6) { return 1; } - brd = KLCF_NEXT(brd); + if (numionodes == numnodes) + brd = KLCF_NEXT_ANY(brd); + else + brd = KLCF_NEXT(brd); + } return 0; } --- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c 2004-02-09 10:39:51.000000000 +0000 @@ -45,7 +45,7 @@ BRIDGE_ISR_PCIBUS_PIOERR; #endif -int pcibr_llp_control_war_cnt; /* PCIBR_LLP_CONTROL_WAR */ +int pcibr_pioerr_dump = 1; /* always dump pio errors */ /* * register values @@ -107,29 +107,22 @@ #define F(s,n) { 1l<<(s),-(s), n } -static struct reg_values space_v[] = -{ - {PCIIO_SPACE_NONE, "none"}, - {PCIIO_SPACE_ROM, "ROM"}, - {PCIIO_SPACE_IO, "I/O"}, - {PCIIO_SPACE_MEM, "MEM"}, - {PCIIO_SPACE_MEM32, "MEM(32)"}, - {PCIIO_SPACE_MEM64, "MEM(64)"}, - {PCIIO_SPACE_CFG, "CFG"}, - {PCIIO_SPACE_WIN(0), "WIN(0)"}, - {PCIIO_SPACE_WIN(1), "WIN(1)"}, - {PCIIO_SPACE_WIN(2), "WIN(2)"}, - {PCIIO_SPACE_WIN(3), "WIN(3)"}, - {PCIIO_SPACE_WIN(4), "WIN(4)"}, - {PCIIO_SPACE_WIN(5), "WIN(5)"}, - {PCIIO_SPACE_BAD, "BAD"}, - {0} -}; -struct reg_desc space_desc[] = -{ - {0xFF, 0, "space", 0, space_v}, - {0} -}; +char *pci_space[] = {"NONE", + "ROM", + "IO", + "", + "MEM", + "MEM32", + "MEM64", + "CFG", + "WIN0", + "WIN1", + "WIN2", + "WIN3", + "WIN4", + "WIN5", + "", + "BAD"}; static char *pcibr_isr_errs[] = { @@ -261,7 +254,7 @@ static void pcibr_show_dir_state(paddr_t paddr, char *prefix) { -#ifdef LATER +#ifdef PCIBR_LATER int state; uint64_t vec_ptr; hubreg_t elo; @@ -270,15 +263,18 @@ get_dir_ent(paddr, &state, &vec_ptr, &elo); - printk("%saddr 0x%lx: state 0x%x owner 0x%lx (%s)\n", - prefix, paddr, state, vec_ptr, dir_state_str[state]); -#endif + printf("%saddr 0x%lx: state 0x%x owner 0x%lx (%s)\n", + prefix, (uint64_t)paddr, state, (uint64_t)vec_ptr, + dir_state_str[state]); +#endif /* PCIBR_LATER */ } -static void -print_bridge_errcmd(uint32_t cmdword, char *errtype) + +void +print_bridge_errcmd(pcibr_soft_t pcibr_soft, uint32_t cmdword, char *errtype) { - printk("\t Bridge %s Error Command Word Register ", errtype); + printk( + "\t Bridge %sError Command Word Register ", errtype); print_register(cmdword, xtalk_cmd_bits); } @@ -290,20 +286,12 @@ void pcibr_error_dump(pcibr_soft_t pcibr_soft) { - bridge_t *bridge = pcibr_soft->bs_base; uint64_t int_status; - picreg_t int_status_64; uint64_t mult_int; - picreg_t mult_int_64; uint64_t bit; - int number_bits; int i; - char *reg_desc; - paddr_t addr = (paddr_t)0; - int_status_64 = (bridge->p_int_status_64 & ~BRIDGE_ISR_INT_MSK); - int_status = (uint64_t)int_status_64; - number_bits = PCIBR_ISR_MAX_ERRS_PIC; + int_status = (pcireg_intr_status_get(pcibr_soft) & ~BRIDGE_ISR_INT_MSK); if (!int_status) { /* No error bits set */ @@ -320,21 +308,11 @@ int_status, pcibr_soft->bs_name, "PIC"); - for (i = PCIBR_ISR_ERR_START; i < number_bits; i++) { + for (i = PCIBR_ISR_ERR_START; i < 64; i++) { bit = 1ull << i; - /* - * A number of int_status bits are only defined for Bridge. - * Ignore them in the case of an XBridge or PIC. - */ - if (((bit == BRIDGE_ISR_MULTI_ERR) || - (bit == BRIDGE_ISR_SSRAM_PERR) || - (bit == BRIDGE_ISR_GIO_B_ENBL_ERR))) { - continue; - } - /* A number of int_status bits are only valid for PIC's bus0 */ - if (((pcibr_soft->bs_busnum != 0)) && + if ((pcibr_soft->bs_busnum != 0) && ((bit == BRIDGE_ISR_UNSUPPORTED_XOP) || (bit == BRIDGE_ISR_LLP_REC_SNERR) || (bit == BRIDGE_ISR_LLP_REC_CBERR) || @@ -351,14 +329,14 @@ case PIC_ISR_INT_RAM_PERR: /* bit41 INT_RAM_PERR */ /* XXX: should breakdown meaning of bits in reg */ - printk( "\t Internal RAM Parity Error: 0x%lx\n", - bridge->p_ate_parity_err_64); + printk("\t Internal RAM Parity Error: 0x%lx\n", + pcireg_parity_err_get(pcibr_soft)); break; case PIC_ISR_PCIX_ARB_ERR: /* bit40 PCI_X_ARB_ERR */ /* XXX: should breakdown meaning of bits in reg */ - printk( "\t Arbitration Reg: 0x%lx\n", - bridge->b_arb); + printk("\t Arbitration Reg: 0x%lx\n", + pcireg_arbitration_get(pcibr_soft)); break; case PIC_ISR_PCIX_REQ_TOUT: /* bit39 PCI_X_REQ_TOUT */ @@ -366,8 +344,8 @@ printk( "\t PCI-X DMA Request Error Address Reg: 0x%lx\n" "\t PCI-X DMA Request Error Attribute Reg: 0x%lx\n", - bridge->p_pcix_dma_req_err_addr_64, - bridge->p_pcix_dma_req_err_attr_64); + pcireg_pcix_req_err_addr_get(pcibr_soft), + pcireg_pcix_req_err_attr_get(pcibr_soft)); break; case PIC_ISR_PCIX_SPLIT_MSG_PE: /* bit45 PCI_X_SPLIT_MES_PE */ @@ -377,8 +355,8 @@ printk( "\t PCI-X Split Request Address Reg: 0x%lx\n" "\t PCI-X Split Request Attribute Reg: 0x%lx\n", - bridge->p_pcix_pio_split_addr_64, - bridge->p_pcix_pio_split_attr_64); + pcireg_pcix_pio_split_addr_get(pcibr_soft), + pcireg_pcix_pio_split_attr_get(pcibr_soft)); /* FALL THRU */ case PIC_ISR_PCIX_UNEX_COMP: /* bit42 PCI_X_UNEX_COMP */ @@ -394,20 +372,19 @@ "\t PCI-X Bus Error Address Reg: 0x%lx\n" "\t PCI-X Bus Error Attribute Reg: 0x%lx\n" "\t PCI-X Bus Error Data Reg: 0x%lx\n", - bridge->p_pcix_bus_err_addr_64, - bridge->p_pcix_bus_err_attr_64, - bridge->p_pcix_bus_err_data_64); + pcireg_pcix_bus_err_addr_get(pcibr_soft), + pcireg_pcix_bus_err_attr_get(pcibr_soft), + pcireg_pcix_bus_err_data_get(pcibr_soft)); break; - case BRIDGE_ISR_PAGE_FAULT: /* bit30 PMU_PAGE_FAULT */ - reg_desc = "Map Fault Address"; - - printk( "\t %s Register: 0x%x\n", reg_desc, - bridge->b_ram_perr_or_map_fault); + case BRIDGE_ISR_PAGE_FAULT: /* bit30 PMU_PAGE_FAULT */ + printk("\t Map Fault Address Reg: 0x%lx\n", + pcireg_map_fault_get(pcibr_soft)); break; - case BRIDGE_ISR_UNEXP_RESP: /* bit29 UNEXPECTED_RESP */ - print_bridge_errcmd(bridge->b_wid_aux_err, "Aux "); + case BRIDGE_ISR_UNEXP_RESP: /* bit29 UNEXPECTED_RESP */ + print_bridge_errcmd(pcibr_soft, + pcireg_linkside_err_get(pcibr_soft), "Aux "); /* PIC in PCI-X mode, dump the PCIX DMA Request registers */ if (IS_PCIX(pcibr_soft)) { @@ -415,96 +392,98 @@ printk( "\t PCI-X DMA Request Error Addr Reg: 0x%lx\n" "\t PCI-X DMA Request Error Attr Reg: 0x%lx\n", - bridge->p_pcix_dma_req_err_addr_64, - bridge->p_pcix_dma_req_err_attr_64); + pcireg_pcix_req_err_addr_get(pcibr_soft), + pcireg_pcix_req_err_attr_get(pcibr_soft)); } break; - case BRIDGE_ISR_BAD_XRESP_PKT: /* bit28 BAD_RESP_PACKET */ - case BRIDGE_ISR_RESP_XTLK_ERR: /* bit26 RESP_XTALK_ERROR */ - print_bridge_errcmd(bridge->b_wid_aux_err, "Aux "); + case BRIDGE_ISR_BAD_XRESP_PKT: /* bit28 BAD_RESP_PACKET */ + case BRIDGE_ISR_RESP_XTLK_ERR: /* bit26 RESP_XTALK_ERROR */ + print_bridge_errcmd(pcibr_soft, + pcireg_linkside_err_get(pcibr_soft), "Aux "); - /* XXX: should breakdown meaning of attribute bit */ - printk( + /* PCI-X mode, DMA Request Error registers are valid. But + * in PCI mode, Response Buffer Address register are valid. + */ + if (IS_PCIX(pcibr_soft)) { + /* XXX: should breakdown meaning of attribute bit */ + printk( "\t PCI-X DMA Request Error Addr Reg: 0x%lx\n" "\t PCI-X DMA Request Error Attribute Reg: 0x%lx\n", - bridge->p_pcix_dma_req_err_addr_64, - bridge->p_pcix_dma_req_err_attr_64); - if (bit == BRIDGE_ISR_RESP_XTLK_ERR) { + pcireg_pcix_req_err_addr_get(pcibr_soft), + pcireg_pcix_req_err_attr_get(pcibr_soft)); + } else { + printk( + "\t Bridge Response Buf Error Addr Reg: 0x%lx\n" + "\t dev-num %d buff-num %d addr 0x%lx\n", + pcireg_resp_err_get(pcibr_soft), + (int)pcireg_resp_err_dev_get(pcibr_soft), + (int)pcireg_resp_err_buf_get(pcibr_soft), + pcireg_resp_err_addr_get(pcibr_soft)); + if (bit == BRIDGE_ISR_RESP_XTLK_ERR) { /* display memory directory associated with cacheline */ - pcibr_show_dir_state(addr, "\t "); + pcibr_show_dir_state( + pcireg_resp_err_get(pcibr_soft), "\t "); + } } break; - case BRIDGE_ISR_BAD_XREQ_PKT: /* bit27 BAD_XREQ_PACKET */ - case BRIDGE_ISR_REQ_XTLK_ERR: /* bit25 REQ_XTALK_ERROR */ - case BRIDGE_ISR_INVLD_ADDR: /* bit24 INVALID_ADDRESS */ - print_bridge_errcmd(bridge->b_wid_err_cmdword, ""); - printk( - "\t Bridge Error Upper Address Register: 0x%lx\n" - "\t Bridge Error Lower Address Register: 0x%lx\n" + case BRIDGE_ISR_BAD_XREQ_PKT: /* bit27 BAD_XREQ_PACKET */ + case BRIDGE_ISR_REQ_XTLK_ERR: /* bit25 REQ_XTALK_ERROR */ + case BRIDGE_ISR_INVLD_ADDR: /* bit24 INVALID_ADDRESS */ + print_bridge_errcmd(pcibr_soft, + pcireg_cmdword_err_get(pcibr_soft), ""); + printk( + "\t Bridge Error Address Register: 0x%lx\n" "\t Bridge Error Address: 0x%lx\n", - (uint64_t) bridge->b_wid_err_upper, - (uint64_t) bridge->b_wid_err_lower, - (((uint64_t) bridge->b_wid_err_upper << 32) | - bridge->b_wid_err_lower)); + pcireg_bus_err_get(pcibr_soft), + pcireg_bus_err_get(pcibr_soft)); break; - case BRIDGE_ISR_UNSUPPORTED_XOP:/* bit23 UNSUPPORTED_XOP */ - print_bridge_errcmd(bridge->b_wid_aux_err, "Aux "); - printk( - "\t Address Holding Link Side Error Reg: 0x%lx\n", - bridge->p_addr_lkerr_64); + case BRIDGE_ISR_UNSUPPORTED_XOP: /* bit23 UNSUPPORTED_XOP */ + print_bridge_errcmd(pcibr_soft, + pcireg_linkside_err_get(pcibr_soft), "Aux "); + printk("\t Address Holding Link Side Error Reg: 0x%lx\n", + pcireg_linkside_err_addr_get(pcibr_soft)); break; - case BRIDGE_ISR_XREQ_FIFO_OFLOW:/* bit22 XREQ_FIFO_OFLOW */ - print_bridge_errcmd(bridge->b_wid_aux_err, "Aux "); - printk( - "\t Address Holding Link Side Error Reg: 0x%lx\n", - bridge->p_addr_lkerr_64); + case BRIDGE_ISR_XREQ_FIFO_OFLOW: /* bit22 XREQ_FIFO_OFLOW */ + print_bridge_errcmd(pcibr_soft, + pcireg_linkside_err_get(pcibr_soft), "Aux "); + printk("\t Address Holding Link Side Error Reg: 0x%lx\n", + pcireg_linkside_err_addr_get(pcibr_soft)); break; - case BRIDGE_ISR_PCI_ABORT: /* bit15 PCI_ABORT */ - case BRIDGE_ISR_PCI_PARITY: /* bit14 PCI_PARITY */ - case BRIDGE_ISR_PCI_SERR: /* bit13 PCI_SERR */ - case BRIDGE_ISR_PCI_PERR: /* bit12 PCI_PERR */ - case BRIDGE_ISR_PCI_MST_TIMEOUT:/* bit11 PCI_MASTER_TOUT */ - case BRIDGE_ISR_PCI_RETRY_CNT: /* bit10 PCI_RETRY_CNT */ - case BRIDGE_ISR_GIO_B_ENBL_ERR: /* bit08 GIO BENABLE_ERR */ - printk( - "\t PCI Error Upper Address Register: 0x%lx\n" - "\t PCI Error Lower Address Register: 0x%lx\n" + case BRIDGE_ISR_PCI_ABORT: /* bit15 PCI_ABORT */ + case BRIDGE_ISR_PCI_PARITY: /* bit14 PCI_PARITY */ + case BRIDGE_ISR_PCI_SERR: /* bit13 PCI_SERR */ + case BRIDGE_ISR_PCI_PERR: /* bit12 PCI_PERR */ + case BRIDGE_ISR_PCI_MST_TIMEOUT: /* bit11 PCI_MASTER_TOUT */ + case BRIDGE_ISR_PCI_RETRY_CNT: /* bit10 PCI_RETRY_CNT */ + printk("\t PCI Error Address Register: 0x%lx\n" "\t PCI Error Address: 0x%lx\n", - (uint64_t) bridge->b_pci_err_upper, - (uint64_t) bridge->b_pci_err_lower, - (((uint64_t) bridge->b_pci_err_upper << 32) | - bridge->b_pci_err_lower)); + pcireg_pci_bus_addr_get(pcibr_soft), + pcireg_pci_bus_addr_addr_get(pcibr_soft)); break; - case BRIDGE_ISR_XREAD_REQ_TIMEOUT: /* bit09 XREAD_REQ_TOUT */ - addr = (((uint64_t)(bridge->b_wid_resp_upper & 0xFFFF) << 32) - | bridge->b_wid_resp_lower); - printk( - "\t Bridge Response Buf Error Upper Addr Reg: 0x%x\n" - "\t Bridge Response Buf Error Lower Addr Reg: 0x%x\n" + case BRIDGE_ISR_XREAD_REQ_TIMEOUT: /* bit09 XREAD_REQ_TOUT */ + printk("\t Bridge Response Buf Error Addr Reg: 0x%lx\n" "\t dev-num %d buff-num %d addr 0x%lx\n", - bridge->b_wid_resp_upper, bridge->b_wid_resp_lower, - ((bridge->b_wid_resp_upper >> 20) & 0x3), - ((bridge->b_wid_resp_upper >> 16) & 0xF), - addr); + pcireg_resp_err_get(pcibr_soft), + (int)pcireg_resp_err_dev_get(pcibr_soft), + (int)pcireg_resp_err_buf_get(pcibr_soft), + pcireg_resp_err_get(pcibr_soft)); break; } } } - mult_int_64 = (bridge->p_mult_int_64 & ~BRIDGE_ISR_INT_MSK); - mult_int = (uint64_t)mult_int_64; - number_bits = PCIBR_ISR_MAX_ERRS_PIC; + mult_int = pcireg_intr_multiple_get(pcibr_soft); if (mult_int & ~BRIDGE_ISR_INT_MSK) { - printk( " %s Multiple Interrupt Register is 0x%lx\n", - "PIC", mult_int); - for (i = PCIBR_ISR_ERR_START; i < number_bits; i++) { + printk(" %s Multiple Interrupt Register is 0x%lx\n", + pcibr_soft->bs_asic_name, mult_int); + for (i = PCIBR_ISR_ERR_START; i < 64; i++) { if (mult_int & (1ull << i)) printk( "\t%s\n", pcibr_isr_errs[i]); } @@ -519,11 +498,7 @@ static void pcibr_pioerr_check(pcibr_soft_t soft) { - bridge_t *bridge; - uint64_t int_status; - picreg_t int_status_64; - bridgereg_t pci_err_lower; - bridgereg_t pci_err_upper; + uint64_t int_status; iopaddr_t pci_addr; pciio_slot_t slot; pcibr_piomap_t map; @@ -532,16 +507,10 @@ unsigned win; int func; - bridge = soft->bs_base; - int_status_64 = (bridge->p_int_status_64 & ~BRIDGE_ISR_INT_MSK); - int_status = (uint64_t)int_status_64; + int_status = pcireg_intr_status_get(soft); if (int_status & BRIDGE_ISR_PCIBUS_PIOERR) { - pci_err_lower = bridge->b_pci_err_lower; - pci_err_upper = bridge->b_pci_err_upper; - - pci_addr = pci_err_upper & BRIDGE_ERRUPPR_ADDRMASK; - pci_addr = (pci_addr << 32) | pci_err_lower; + pci_addr = pcireg_pci_bus_addr_get(soft); slot = PCIBR_NUM_SLOTS(soft); while (slot-- > 0) { @@ -564,7 +533,7 @@ else if (map->bp_space == PCIIO_SPACE_ROM) base += pcibr_info->f_rbase; if ((pci_addr >= base) && (pci_addr < (base + size))) - atomic_inc(&map->bp_toc[0]); + atomic_inc(&map->bp_toc); } } } @@ -595,11 +564,9 @@ pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *ep) { pcibr_soft_t pcibr_soft; - bridge_t *bridge; - uint64_t int_status; - uint64_t err_status; - picreg_t int_status_64; - int number_bits; + void *bridge; + uint64_t int_status; + uint64_t err_status; int i; uint64_t disable_errintr_mask = 0; nasid_t nasid; @@ -662,9 +629,7 @@ return(pcibr_error_intr_handler(irq, arg, ep)); } - int_status_64 = (bridge->p_int_status_64 & ~BRIDGE_ISR_INT_MSK); - int_status = (uint64_t)int_status_64; - number_bits = PCIBR_ISR_MAX_ERRS_PIC; + int_status = pcireg_intr_status_get(pcibr_soft); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ERROR, pcibr_soft->bs_conn, "pcibr_error_intr_handler: int_status=0x%lx\n", int_status)); @@ -672,7 +637,7 @@ /* int_status is which bits we have to clear; * err_status is the bits we haven't handled yet. */ - err_status = int_status & ~BRIDGE_ISR_MULTI_ERR; + err_status = int_status; if (!(int_status & ~BRIDGE_ISR_INT_MSK)) { /* @@ -688,9 +653,10 @@ } if (err_status) { - struct bs_errintr_stat_s *bs_estat = pcibr_soft->bs_errintr_stat; + struct bs_errintr_stat_s *bs_estat ; + bs_estat = &pcibr_soft->bs_errintr_stat[PCIBR_ISR_ERR_START]; - for (i = PCIBR_ISR_ERR_START; i < number_bits; i++, bs_estat++) { + for (i = PCIBR_ISR_ERR_START; i < 64; i++, bs_estat++) { if (err_status & (1ull << i)) { uint32_t errrate = 0; uint32_t errcount = 0; @@ -827,7 +793,7 @@ * could eat up too much cpu time. */ s = pcibr_lock(pcibr_soft); - bridge->p_int_enable_64 &= (picreg_t)(~disable_errintr_mask); + pcireg_intr_enable_bit_clr(pcibr_soft, disable_errintr_mask); pcibr_unlock(pcibr_soft, s); } /* @@ -836,31 +802,22 @@ * which will cause a BRIDGE_ISR_INVLD_ADDR. */ if ((err_status & BRIDGE_ISR_INVLD_ADDR) && - (0x00000000 == bridge->b_wid_err_upper) && - (0x00C00000 == (0xFFC00000 & bridge->b_wid_err_lower)) && - (0x00402000 == (0x00F07F00 & bridge->b_wid_err_cmdword))) { + (0x00C00000 == (pcireg_bus_err_get(pcibr_soft) & 0xFFFFFFFFFFC00000)) && + (0x00402000 == (0x00F07F00 & pcireg_cmdword_err_get(pcibr_soft)))) { err_status &= ~BRIDGE_ISR_INVLD_ADDR; } /* - * The bridge bug (PCIBR_LLP_CONTROL_WAR), where the llp_config or control registers - * need to be read back after being written, affects an MP - * system since there could be small windows between writing - * the register and reading it back on one cpu while another - * cpu is fielding an interrupt. If we run into this scenario, - * workaround the problem by ignoring the error. (bug 454474) - * pcibr_llp_control_war_cnt keeps an approximate number of - * times we saw this problem on a system. + * pcibr_pioerr_dump is a systune that make be used to not + * print bridge registers for interrupts generated by pio-errors. + * Some customers do early probes and expect a lot of failed + * pios. */ - - if ((err_status & BRIDGE_ISR_INVLD_ADDR) && - ((((uint64_t) bridge->b_wid_err_upper << 32) | (bridge->b_wid_err_lower)) - == (BRIDGE_INT_RST_STAT & 0xff0))) { - pcibr_llp_control_war_cnt++; - err_status &= ~BRIDGE_ISR_INVLD_ADDR; + if (!pcibr_pioerr_dump) { + bridge_errors_to_dump &= ~BRIDGE_ISR_PCIBUS_PIOERR; + } else { + bridge_errors_to_dump |= BRIDGE_ISR_PCIBUS_PIOERR; } - bridge_errors_to_dump |= BRIDGE_ISR_PCIBUS_PIOERR; - /* Dump/Log Bridge error interrupt info */ if (err_status & bridge_errors_to_dump) { printk("BRIDGE ERR_STATUS 0x%lx\n", err_status); @@ -873,10 +830,11 @@ * has only been seen in simulation */ if (PCIBR_WAR_ENABLED(PV867308, pcibr_soft) && - (err_status & (BRIDGE_ISR_LLP_REC_SNERR | BRIDGE_ISR_LLP_REC_CBERR))) { - printk("BRIDGE ERR_STATUS 0x%lx\n", err_status); - pcibr_error_dump(pcibr_soft); - panic("PCI Bridge Error interrupt killed the system"); + (err_status & (BRIDGE_ISR_LLP_REC_SNERR | BRIDGE_ISR_LLP_REC_CBERR))) { + printk("BRIDGE ERR_STATUS 0x%lx\n", err_status); + pcibr_error_dump(pcibr_soft); + /* machine_error_dump(""); */ + panic("PCI Bridge Error interrupt killed the system"); } if (err_status & BRIDGE_ISR_ERROR_FATAL) { @@ -893,7 +851,7 @@ * * PIC doesn't require groups of interrupts to be cleared... */ - bridge->p_int_rst_stat_64 = (picreg_t)(int_status | BRIDGE_IRR_MULTI_CLR); + pcireg_intr_reset_set(pcibr_soft, (int_status | BRIDGE_IRR_MULTI_CLR)); /* PIC BRINGUP WAR (PV# 856155): * On a PCI_X_ARB_ERR error interrupt clear the DEV_BROKE bits from @@ -901,7 +859,7 @@ */ if ((err_status & PIC_ISR_PCIX_ARB_ERR) && PCIBR_WAR_ENABLED(PV856155, pcibr_soft)) { - bridge->b_arb |= (0xf << 20); + pcireg_arbitration_bit_set(pcibr_soft, (0xf << 20)); } /* Zero out bserr_intstat field */ @@ -909,18 +867,196 @@ return IRQ_HANDLED; } +/* + * pcibr_addr_toslot + * Given the 'pciaddr' find out which slot this address is + * allocated to, and return the slot number. + * While we have the info handy, construct the + * function number, space code and offset as well. + * + * NOTE: if this routine is called, we don't know whether + * the address is in CFG, MEM, or I/O space. We have to guess. + * This will be the case on PIO stores, where the only way + * we have of getting the address is to check the Bridge, which + * stores the PCI address but not the space and not the xtalk + * address (from which we could get it). + */ +static int +pcibr_addr_toslot(pcibr_soft_t pcibr_soft, + iopaddr_t pciaddr, + pciio_space_t *spacep, + iopaddr_t *offsetp, + pciio_function_t *funcp) +{ + int s, f = 0, w; + iopaddr_t base; + size_t size; + pciio_piospace_t piosp; + + /* + * Check if the address is in config space + */ + + if ((pciaddr >= BRIDGE_CONFIG_BASE) && (pciaddr < BRIDGE_CONFIG_END)) { + + if (pciaddr >= BRIDGE_CONFIG1_BASE) + pciaddr -= BRIDGE_CONFIG1_BASE; + else + pciaddr -= BRIDGE_CONFIG_BASE; + + s = pciaddr / BRIDGE_CONFIG_SLOT_SIZE; + pciaddr %= BRIDGE_CONFIG_SLOT_SIZE; + + if (funcp) { + f = pciaddr / 0x100; + pciaddr %= 0x100; + } + if (spacep) + *spacep = PCIIO_SPACE_CFG; + if (offsetp) + *offsetp = pciaddr; + if (funcp) + *funcp = f; + + return s; + } + for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) { + int nf = pcibr_soft->bs_slot[s].bss_ninfo; + pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos; + + for (f = 0; f < nf; f++) { + pcibr_info_t pcibr_info = pcibr_infoh[f]; + + if (!pcibr_info) + continue; + for (w = 0; w < 6; w++) { + if (pcibr_info->f_window[w].w_space + == PCIIO_SPACE_NONE) { + continue; + } + base = pcibr_info->f_window[w].w_base; + size = pcibr_info->f_window[w].w_size; + + if ((pciaddr >= base) && (pciaddr < (base + size))) { + if (spacep) + *spacep = PCIIO_SPACE_WIN(w); + if (offsetp) + *offsetp = pciaddr - base; + if (funcp) + *funcp = f; + return s; + } /* endif match */ + } /* next window */ + } /* next func */ + } /* next slot */ + + /* + * Check if the address was allocated as part of the + * pcibr_piospace_alloc calls. + */ + for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) { + int nf = pcibr_soft->bs_slot[s].bss_ninfo; + pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos; + + for (f = 0; f < nf; f++) { + pcibr_info_t pcibr_info = pcibr_infoh[f]; + + if (!pcibr_info) + continue; + piosp = pcibr_info->f_piospace; + while (piosp) { + if ((piosp->start <= pciaddr) && + ((piosp->count + piosp->start) > pciaddr)) { + if (spacep) + *spacep = piosp->space; + if (offsetp) + *offsetp = pciaddr - piosp->start; + return s; + } /* endif match */ + piosp = piosp->next; + } /* next piosp */ + } /* next func */ + } /* next slot */ + + /* + * Some other random address on the PCI bus ... + * we have no way of knowing whether this was + * a MEM or I/O access; so, for now, we just + * assume that the low 1G is MEM, the next + * 3G is I/O, and anything above the 4G limit + * is obviously MEM. + */ + + if (spacep) + *spacep = ((pciaddr < (1ul << 30)) ? PCIIO_SPACE_MEM : + (pciaddr < (4ul << 30)) ? PCIIO_SPACE_IO : + PCIIO_SPACE_MEM); + if (offsetp) + *offsetp = pciaddr; + + return PCIIO_SLOT_NONE; + +} + void pcibr_error_cleanup(pcibr_soft_t pcibr_soft, int error_code) { - bridge_t *bridge = pcibr_soft->bs_base; + uint64_t clr_bits = BRIDGE_IRR_ALL_CLR; ASSERT(error_code & IOECODE_PIO); error_code = error_code; - bridge->p_int_rst_stat_64 = BRIDGE_IRR_PCI_GRP_CLR | - PIC_PCIX_GRP_CLR | - BRIDGE_IRR_MULTI_CLR; - (void) bridge->b_wid_tflush; /* flushbus */ + pcireg_intr_reset_set(pcibr_soft, clr_bits); + + pcireg_tflush_get(pcibr_soft); /* flushbus */ +} + + +/* + * pcibr_error_extract + * Given the 'pcibr vertex handle' find out which slot + * the bridge status error address (from pcibr_soft info + * hanging off the vertex) + * allocated to, and return the slot number. + * While we have the info handy, construct the + * space code and offset as well. + * + * NOTE: if this routine is called, we don't know whether + * the address is in CFG, MEM, or I/O space. We have to guess. + * This will be the case on PIO stores, where the only way + * we have of getting the address is to check the Bridge, which + * stores the PCI address but not the space and not the xtalk + * address (from which we could get it). + * + * XXX- this interface has no way to return the function + * number on a multifunction card, even though that data + * is available. + */ + +pciio_slot_t +pcibr_error_extract(vertex_hdl_t pcibr_vhdl, + pciio_space_t *spacep, + iopaddr_t *offsetp) +{ + pcibr_soft_t pcibr_soft = 0; + iopaddr_t bserr_addr; + pciio_slot_t slot = PCIIO_SLOT_NONE; + arbitrary_info_t rev; + + /* Do a sanity check as to whether we really got a + * bridge vertex handle. + */ + if (hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &rev) != + GRAPH_SUCCESS) + return(slot); + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + if (pcibr_soft) { + bserr_addr = pcireg_pci_bus_addr_get(pcibr_soft); + slot = pcibr_addr_toslot(pcibr_soft, bserr_addr, + spacep, offsetp, NULL); + } + return slot; } /*ARGSUSED */ @@ -953,6 +1089,28 @@ * to handle the error, it expects the bus-interface to disable that * device, and takes any steps needed here to take away any resources * associated with this device. + * + * A note about slots: + * + * PIC-based bridges use zero-based device numbering when devices to + * internal registers. However, the physical slots are numbered using a + * one-based scheme because in PCI-X, device 0 is reserved (see comments + * in pcibr_private.h for a better description). + * + * When building up the hwgraph, we use the external (one-based) number + * scheme when numbering slot components so that hwgraph more accuratly + * reflects what is silkscreened on the bricks. + * + * Since pciio_error_handler() needs to ultimatly be able to do a hwgraph + * lookup, the ioerror that gets built up in pcibr_pioerror() encodes the + * external (one-based) slot number. However, loops in pcibr_pioerror() + * which attempt to translate the virtual address into the correct + * PCI physical address use the device (zero-based) numbering when + * walking through bridge structures. + * + * To that end, pcibr_pioerror() uses device to denote the + * zero-based device number, and external_slot to denote the corresponding + * one-based slot number. Loop counters (eg. cs) are always device based. */ /* BEM_ADD_IOE doesn't dump the whole ioerror, it just @@ -1017,7 +1175,8 @@ iopaddr_t raw_paddr; /* raw PCI address */ pciio_space_t space; /* final PCI space */ - pciio_slot_t slot; /* final PCI slot, if appropriate */ + pciio_slot_t device; /* final PCI device if appropriate */ + pciio_slot_t external_slot;/* external slot for device */ pciio_function_t func; /* final PCI func, if appropriate */ iopaddr_t offset; /* final PCI offset */ @@ -1039,16 +1198,16 @@ "pcibr_pioerror: pcibr_soft=0x%lx, bad_xaddr=0x%lx\n", pcibr_soft, bad_xaddr)); - slot = PCIIO_SLOT_NONE; + device = PCIIO_SLOT_NONE; func = PCIIO_FUNC_NONE; raw_space = PCIIO_SPACE_NONE; raw_paddr = 0; - if ((bad_xaddr >= PCIBR_BUS_TYPE0_CFG_DEV0(pcibr_soft)) && + if ((bad_xaddr >= PCIBR_BUS_TYPE0_CFG_DEV(pcibr_soft, 0)) && (bad_xaddr < PCIBR_TYPE1_CFG(pcibr_soft))) { - raw_paddr = bad_xaddr - PCIBR_BUS_TYPE0_CFG_DEV0(pcibr_soft); - slot = raw_paddr / BRIDGE_TYPE0_CFG_SLOT_OFF; - raw_paddr = raw_paddr % BRIDGE_TYPE0_CFG_SLOT_OFF; + raw_paddr = bad_xaddr - PCIBR_BUS_TYPE0_CFG_DEV(pcibr_soft, 0); + device = raw_paddr / BRIDGE_CONFIG_SLOT_SIZE; + raw_paddr = raw_paddr % BRIDGE_CONFIG_SLOT_SIZE; raw_space = PCIIO_SPACE_CFG; } if ((bad_xaddr >= PCIBR_TYPE1_CFG(pcibr_soft)) && @@ -1060,11 +1219,11 @@ raw_paddr = bad_xaddr - PCIBR_TYPE1_CFG(pcibr_soft); raw_space = PCIIO_SPACE_CFG; } - if ((bad_xaddr >= PCIBR_BRIDGE_DEVIO0(pcibr_soft)) && + if ((bad_xaddr >= PCIBR_BRIDGE_DEVIO(pcibr_soft, 0)) && (bad_xaddr < PCIBR_BRIDGE_DEVIO(pcibr_soft, BRIDGE_DEV_CNT))) { int x; - raw_paddr = bad_xaddr - PCIBR_BRIDGE_DEVIO0(pcibr_soft); + raw_paddr = bad_xaddr - PCIBR_BRIDGE_DEVIO(pcibr_soft, 0); x = raw_paddr / BRIDGE_DEVIO_OFF; raw_paddr %= BRIDGE_DEVIO_OFF; /* first two devio windows are double-sized */ @@ -1101,25 +1260,37 @@ } else raw_paddr += pcibr_soft->bs_slot[x].bss_devio.bssd_base; } - if ((bad_xaddr >= BRIDGE_PCI_MEM32_BASE) && - (bad_xaddr <= BRIDGE_PCI_MEM32_LIMIT)) { - raw_space = PCIIO_SPACE_MEM32; - raw_paddr = bad_xaddr - BRIDGE_PCI_MEM32_BASE; - } - if ((bad_xaddr >= BRIDGE_PCI_MEM64_BASE) && - (bad_xaddr <= BRIDGE_PCI_MEM64_LIMIT)) { - raw_space = PCIIO_SPACE_MEM64; - raw_paddr = bad_xaddr - BRIDGE_PCI_MEM64_BASE; - } - if ((bad_xaddr >= BRIDGE_PCI_IO_BASE) && - (bad_xaddr <= BRIDGE_PCI_IO_LIMIT)) { - raw_space = PCIIO_SPACE_IO; - raw_paddr = bad_xaddr - BRIDGE_PCI_IO_BASE; + + if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 0)) { + if ((bad_xaddr >= PICBRIDGE0_PCI_MEM32_BASE) && + (bad_xaddr <= PICBRIDGE0_PCI_MEM32_LIMIT)) { + raw_space = PCIIO_SPACE_MEM32; + raw_paddr = bad_xaddr - PICBRIDGE0_PCI_MEM32_BASE; + } + if ((bad_xaddr >= PICBRIDGE0_PCI_MEM64_BASE) && + (bad_xaddr <= PICBRIDGE0_PCI_MEM64_LIMIT)) { + raw_space = PCIIO_SPACE_MEM64; + raw_paddr = bad_xaddr - PICBRIDGE0_PCI_MEM64_BASE; + } + } else if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 1)) { + if ((bad_xaddr >= PICBRIDGE1_PCI_MEM32_BASE) && + (bad_xaddr <= PICBRIDGE1_PCI_MEM32_LIMIT)) { + raw_space = PCIIO_SPACE_MEM32; + raw_paddr = bad_xaddr - PICBRIDGE1_PCI_MEM32_BASE; + } + if ((bad_xaddr >= PICBRIDGE1_PCI_MEM64_BASE) && + (bad_xaddr <= PICBRIDGE1_PCI_MEM64_LIMIT)) { + raw_space = PCIIO_SPACE_MEM64; + raw_paddr = bad_xaddr - PICBRIDGE1_PCI_MEM64_BASE; + } + } else { + printk("pcibr_pioerror(): unknown bridge type"); + return IOERROR_UNHANDLED; } space = raw_space; offset = raw_paddr; - if ((slot == PCIIO_SLOT_NONE) && (space != PCIIO_SPACE_NONE)) { + if ((device == PCIIO_SLOT_NONE) && (space != PCIIO_SPACE_NONE)) { /* we've got a space/offset but not which * PCI slot decodes it. Check through our * notions of which devices decode where. @@ -1133,16 +1304,16 @@ for (cs = pcibr_soft->bs_min_slot; (cs < PCIBR_NUM_SLOTS(pcibr_soft)) && - (slot == PCIIO_SLOT_NONE); cs++) { + (device == PCIIO_SLOT_NONE); cs++) { int nf = pcibr_soft->bs_slot[cs].bss_ninfo; pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos; - for (cf = 0; (cf < nf) && (slot == PCIIO_SLOT_NONE); cf++) { + for (cf = 0; (cf < nf) && (device == PCIIO_SLOT_NONE); cf++) { pcibr_info_t pcibr_info = pcibr_infoh[cf]; if (!pcibr_info) continue; - for (cw = 0; (cw < 6) && (slot == PCIIO_SLOT_NONE); ++cw) { + for (cw = 0; (cw < 6) && (device == PCIIO_SLOT_NONE); ++cw) { if (((wx = pcibr_info->f_window[cw].w_space) != PCIIO_SPACE_NONE) && ((wb = pcibr_info->f_window[cw].w_base) != 0) && ((ws = pcibr_info->f_window[cw].w_size) != 0) && @@ -1158,7 +1329,7 @@ ((space == PCIIO_SPACE_MEM) || (space == PCIIO_SPACE_MEM32) || (space == PCIIO_SPACE_MEM64)))) { - slot = cs; + device = cs; func = cf; space = PCIIO_SPACE_WIN(cw); offset -= wb; @@ -1211,7 +1382,7 @@ wb = map->bp_pciaddr; ws = map->bp_mapsz; cw = wx - PCIIO_SPACE_WIN(0); - if (cw < 6) { + if (cw >= 0 && cw < 6) { wb += pcibr_soft->bs_slot[cs].bss_window[cw].bssw_base; wx = pcibr_soft->bs_slot[cs].bss_window[cw].bssw_space; } @@ -1224,32 +1395,35 @@ wx = PCIIO_SPACE_MEM; wl = wb + ws; if ((wx == raw_space) && (raw_paddr >= wb) && (raw_paddr < wl)) { - atomic_inc(&map->bp_toc[0]); - if (slot == PCIIO_SLOT_NONE) { - slot = cs; + atomic_inc(&map->bp_toc); + if (device == PCIIO_SLOT_NONE) { + device = cs; + func = cf; space = map->bp_space; - if (cw < 6) - offset -= pcibr_soft->bs_slot[cs].bss_window[cw].bssw_base; + if (cw >= 0 && cw < 6) + offset -= pcibr_soft->bs_slot[device].bss_window[cw].bssw_base; } + + break; } } } } PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn, - "pcibr_pioerror: offset=0x%x, slot=0x%x, func=0x%x\n", - offset, slot, func)); + "pcibr_pioerror: space=%d, offset=0x%lx, dev=0x%x, func=0x%x\n", + space, offset, device, func)); if (space != PCIIO_SPACE_NONE) { - if (slot != PCIIO_SLOT_NONE) { - if (func != PCIIO_FUNC_NONE) { + if (device != PCIIO_SLOT_NONE) { + external_slot = PCIBR_DEVICE_TO_SLOT(pcibr_soft, device); + + if (func != PCIIO_FUNC_NONE) IOERROR_SETVALUE(ioe, widgetdev, - pciio_widgetdev_create(slot,func)); - } - else { + pciio_widgetdev_create(external_slot,func)); + else IOERROR_SETVALUE(ioe, widgetdev, - pciio_widgetdev_create(slot,0)); - } + pciio_widgetdev_create(external_slot,0)); } IOERROR_SETVALUE(ioe, busspace, space); IOERROR_SETVALUE(ioe, busaddr, offset); @@ -1265,7 +1439,7 @@ /* if appropriate, give the error handler for this slot * a shot at this probe access as well. */ - return (slot == PCIIO_SLOT_NONE) ? IOERROR_HANDLED : + return (device == PCIIO_SLOT_NONE) ? IOERROR_HANDLED : pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); } /* @@ -1355,10 +1529,11 @@ * other errors. */ if (IOERROR_FIELDVALID(ioe, widgetdev)) { - short widdev; - IOERROR_GETVALUE(widdev, ioe, widgetdev); - pcibr_device_disable(pcibr_soft, - pciio_widgetdev_slot_get(widdev)); + short widdev; + IOERROR_GETVALUE(widdev, ioe, widgetdev); + external_slot = pciio_widgetdev_slot_get(widdev); + device = PCIBR_SLOT_TO_DEVICE(pcibr_soft, external_slot); + pcibr_device_disable(pcibr_soft, device); } if (mode == MODE_DEVUSERERROR) pcibr_error_cleanup(pcibr_soft, error_code); @@ -1381,10 +1556,8 @@ ioerror_t *ioe) { vertex_hdl_t pcibr_vhdl = pcibr_soft->bs_vhdl; - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t bus_lowaddr, bus_uppraddr; int retval = 0; - int bufnum; + int bufnum, device; /* * In case of DMA errors, bridge should have logged the @@ -1401,19 +1574,10 @@ /* * read error log registers */ - bus_lowaddr = bridge->b_wid_resp_lower; - bus_uppraddr = bridge->b_wid_resp_upper; - - bufnum = BRIDGE_RESP_ERRUPPR_BUFNUM(bus_uppraddr); - IOERROR_SETVALUE(ioe, widgetdev, - pciio_widgetdev_create( - BRIDGE_RESP_ERRUPPR_DEVICE(bus_uppraddr), - 0)); - IOERROR_SETVALUE(ioe, busaddr, - (bus_lowaddr | - ((iopaddr_t) - (bus_uppraddr & - BRIDGE_ERRUPPR_ADDRMASK) << 32))); + bufnum = pcireg_resp_err_buf_get(pcibr_soft); + device = pcireg_resp_err_dev_get(pcibr_soft); + IOERROR_SETVALUE(ioe, widgetdev, pciio_widgetdev_create(device, 0)); + IOERROR_SETVALUE(ioe, busaddr, pcireg_resp_err_get(pcibr_soft)); /* * need to ensure that the xtalk address in ioe @@ -1436,7 +1600,7 @@ * not is dependent on INT_ENABLE register. This write just makes sure * that if the interrupt was enabled, we do get the interrupt. */ - bridge->b_int_rst_stat = BRIDGE_IRR_RESP_BUF_GRP_CLR; + pcireg_intr_reset_set(pcibr_soft, BRIDGE_IRR_RESP_BUF_GRP_CLR); /* * Also, release the "bufnum" back to buffer pool that could be re-used. @@ -1445,19 +1609,13 @@ */ { - reg_p regp; - bridgereg_t regv; - bridgereg_t mask; - - regp = (bufnum & 1) - ? &bridge->b_odd_resp - : &bridge->b_even_resp; + uint64_t rrb_reg; + uint64_t mask; + rrb_reg = pcireg_rrb_get(pcibr_soft, (bufnum & 1)); mask = 0xF << ((bufnum >> 1) * 4); - - regv = *regp; - *regp = regv & ~mask; - *regp = regv; + pcireg_rrb_set(pcibr_soft, (bufnum & 1), (rrb_reg & ~mask)); + pcireg_rrb_set(pcibr_soft, (bufnum & 1), rrb_reg); } return retval; @@ -1705,9 +1863,9 @@ */ if ((pio_retval == -1) && (dma_retval == -1)) { return IOERROR_BADERRORCODE; - } else if (dma_retval != IOERROR_HANDLED) { + } else if ((dma_retval != IOERROR_HANDLED) && (dma_retval != -1)) { return dma_retval; - } else if (pio_retval != IOERROR_HANDLED) { + } else if ((pio_retval != IOERROR_HANDLED) && (pio_retval != -1)) { return pio_retval; } else { return IOERROR_HANDLED; --- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c 2004-02-09 10:39:51.000000000 +0000 @@ -33,8 +33,11 @@ if (alloc && (rv != GRAPH_SUCCESS)) { hint = kmalloc(sizeof (*(hint)), GFP_KERNEL); - if ( !hint ) + if ( !hint ) { + printk(KERN_WARNING "pcibr_hints_get(): unable to allocate " + "memory\n"); goto abnormal_exit; + } memset(hint, 0, sizeof (*(hint))); hint->rrb_alloc_funct = NULL; @@ -57,7 +60,7 @@ abnormal_exit: kfree(hint); - return(NULL); + return NULL; } --- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c 2004-02-09 10:39:51.000000000 +0000 @@ -25,14 +25,14 @@ /* FIXME - compare_and_swap_ptr NOT ATOMIC */ if (*location == old_ptr) { *location = new_ptr; - return(1); + return 1; } else - return(0); + return 0; } #endif -unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines, int nslots); +unsigned int pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines, int nslots); pcibr_intr_t pcibr_intr_alloc(vertex_hdl_t, device_desc_t, pciio_intr_line_t, vertex_hdl_t); void pcibr_intr_free(pcibr_intr_t); void pcibr_setpciint(xtalk_intr_t); @@ -40,8 +40,6 @@ void pcibr_intr_disconnect(pcibr_intr_t); vertex_hdl_t pcibr_intr_cpu_get(pcibr_intr_t); -void pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); -void pcibr_intr_func(intr_arg_t); extern pcibr_info_t pcibr_info_get(vertex_hdl_t); @@ -49,7 +47,7 @@ * INTERRUPT MANAGEMENT */ -unsigned +unsigned int pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines, int nslots) { @@ -100,7 +98,8 @@ extern struct sn_flush_nasid_entry flush_nasid_list[MAX_NASIDS]; void -sn_dma_flush(unsigned long addr) { +sn_dma_flush(unsigned long addr) +{ nasid_t nasid; int wid_num; volatile struct sn_flush_device_list *p; @@ -144,7 +143,7 @@ /* force an interrupt. */ - *(bridgereg_t *)(p->force_int_addr) = 1; + *(volatile uint32_t *)(p->force_int_addr) = 1; /* wait for the interrupt to come back. */ @@ -152,8 +151,6 @@ /* okay, everything is synched up. */ spin_unlock_irqrestore(&p->flush_lock, flags); - - return; } EXPORT_SYMBOL(sn_dma_flush); @@ -200,7 +197,6 @@ unsigned bit; unsigned bits; pcibr_soft_t pcibr_soft = intr->bi_soft; - bridge_t *bridge = pcibr_soft->bs_base; bits = intr->bi_ibits; for (bit = 0; bit < 8; bit++) { @@ -209,7 +205,7 @@ PCIBR_DEBUG((PCIBR_DEBUG_INTR, pcibr_soft->bs_vhdl, "pcibr_force_interrupt: bit=0x%x\n", bit)); - bridge->b_force_pin[bit].intr = 1; + pcireg_force_intr_set(pcibr_soft, bit); } } } @@ -225,7 +221,6 @@ pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; - bridge_t *bridge = pcibr_soft->bs_base; int is_threaded = 0; xtalk_intr_t *xtalk_intr_p; @@ -239,8 +234,6 @@ pcibr_intr_t pcibr_intr; pcibr_intr_list_t intr_entry; pcibr_intr_list_t intr_list; - bridgereg_t int_dev; - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, "pcibr_intr_alloc: %s%s%s%s%s\n", @@ -266,9 +259,9 @@ pcibr_intr->bi_ibuf.ib_in = 0; pcibr_intr->bi_ibuf.ib_out = 0; spin_lock_init(&pcibr_intr->bi_ibuf.ib_lock); - pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines, - PCIBR_NUM_SLOTS(pcibr_soft)); + pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, + lines, PCIBR_NUM_SLOTS(pcibr_soft)); /* * For each PCI interrupt line requested, figure @@ -336,10 +329,10 @@ * now tell the bridge which slot is * using this interrupt line. */ - int_dev = bridge->b_int_device; - int_dev &= ~BRIDGE_INT_DEV_MASK(pcibr_int_bit); - int_dev |= pciio_slot << BRIDGE_INT_DEV_SHFT(pcibr_int_bit); - bridge->b_int_device = int_dev; /* XXXMP */ + pcireg_intr_device_bit_clr(pcibr_soft, + BRIDGE_INT_DEV_MASK(pcibr_int_bit)); + pcireg_intr_device_bit_set(pcibr_soft, + (pciio_slot << BRIDGE_INT_DEV_SHFT(pcibr_int_bit))); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, "bridge intr bit %d clears my wrb\n", @@ -367,7 +360,8 @@ intr_entry->il_next = NULL; intr_entry->il_intr = pcibr_intr; - intr_entry->il_wrbf = &(bridge->b_wr_req_buf[pciio_slot].reg); + intr_entry->il_soft = pcibr_soft; + intr_entry->il_slot = pciio_slot; intr_list_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; @@ -479,19 +473,14 @@ if ((!intr_shared) && (*xtalk_intrp)) { - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t int_dev; - xtalk_intr_free(*xtalk_intrp); *xtalk_intrp = 0; /* Clear the PCI device interrupt to bridge interrupt pin * mapping. */ - int_dev = bridge->b_int_device; - int_dev &= ~BRIDGE_INT_DEV_MASK(pcibr_int_bit); - bridge->b_int_device = int_dev; - + pcireg_intr_device_bit_clr(pcibr_soft, + BRIDGE_INT_DEV_MASK(pcibr_int_bit)); } } } @@ -504,17 +493,21 @@ iopaddr_t addr; xtalk_intr_vector_t vect; vertex_hdl_t vhdl; - bridge_t *bridge; - picreg_t *int_addr; - + int bus_num; + int pcibr_int_bit; + void *bridge; + addr = xtalk_intr_addr_get(xtalk_intr); vect = xtalk_intr_vector_get(xtalk_intr); vhdl = xtalk_intr_dev_get(xtalk_intr); - bridge = (bridge_t *)xtalk_piotrans_addr(vhdl, 0, 0, sizeof(bridge_t), 0); - int_addr = (picreg_t *)xtalk_intr_sfarg_get(xtalk_intr); - *int_addr = ((PIC_INT_ADDR_FLD & ((uint64_t)vect << 48)) | - (PIC_INT_ADDR_HOST & addr)); + /* bus and int_bits are stored in sfarg, bus bit3, int_bits bit2:0 */ + pcibr_int_bit = *((int *)xtalk_intr_sfarg_get(xtalk_intr)) & 0x7; + bus_num = ((*((int *)xtalk_intr_sfarg_get(xtalk_intr)) & 0x8) >> 3); + + bridge = pcibr_bridge_ptr_get(vhdl, bus_num); + pcireg_bridge_intr_addr_vect_set(bridge, pcibr_int_bit, vect); + pcireg_bridge_intr_addr_addr_set(bridge, pcibr_int_bit, addr); } /*ARGSUSED */ @@ -522,11 +515,9 @@ pcibr_intr_connect(pcibr_intr_t pcibr_intr, intr_func_t intr_func, intr_arg_t intr_arg) { pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - bridge_t *bridge = pcibr_soft->bs_base; unsigned pcibr_int_bits = pcibr_intr->bi_ibits; unsigned pcibr_int_bit; - uint64_t int_enable; - unsigned long s; + unsigned long s; if (pcibr_intr == NULL) return -1; @@ -566,37 +557,27 @@ * Use the pcibr wrapper function to handle all Bridge interrupts * regardless of whether the interrupt line is shared or not. */ - int_addr = (void *)&(bridge->p_int_addr_64[pcibr_int_bit]); - - xtalk_intr_connect(xtalk_intr, pcibr_intr_func, (intr_arg_t) intr_wrap, - (xtalk_intr_setfunc_t) pcibr_setpciint, - (void *)int_addr); + int_addr = pcireg_intr_addr_addr(pcibr_soft, pcibr_int_bit); + pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit = + ((pcibr_soft->bs_busnum << 3) | pcibr_int_bit); + xtalk_intr_connect(xtalk_intr, + NULL, + (intr_arg_t) intr_wrap, + (xtalk_intr_setfunc_t) pcibr_setpciint, + &pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit); pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, - "pcibr_setpciint: int_addr=0x%x, *int_addr=0x%x, " - "pcibr_int_bit=0x%x\n", int_addr, - *(picreg_t *)int_addr, + "pcibr_setpciint: int_addr=0x%lx, *int_addr=0x%lx, " + "pcibr_int_bit=0x%x\n", int_addr, + pcireg_intr_addr_get(pcibr_soft, pcibr_int_bit), pcibr_int_bit)); } - /* PIC WAR. PV# 854697 - * On PIC we must write 64-bit MMRs with 64-bit stores - */ s = pcibr_lock(pcibr_soft); - if (PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) { - int_enable = bridge->p_int_enable_64; - int_enable |= pcibr_int_bits; - bridge->p_int_enable_64 = int_enable; - } else { - bridgereg_t int_enable; - - int_enable = bridge->b_int_enable; - int_enable |= pcibr_int_bits; - bridge->b_int_enable = int_enable; - } - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + pcireg_intr_enable_bit_set(pcibr_soft, pcibr_int_bits); + pcireg_tflush_get(pcibr_soft); pcibr_unlock(pcibr_soft, s); return 0; @@ -607,12 +588,10 @@ pcibr_intr_disconnect(pcibr_intr_t pcibr_intr) { pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - bridge_t *bridge = pcibr_soft->bs_base; unsigned pcibr_int_bits = pcibr_intr->bi_ibits; unsigned pcibr_int_bit; - pcibr_intr_wrap_t intr_wrap; - uint64_t int_enable; - unsigned long s; + pcibr_intr_wrap_t intr_wrap; + unsigned long s; /* Stop calling the function. Now. */ @@ -636,16 +615,8 @@ return; s = pcibr_lock(pcibr_soft); - if (PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) { - int_enable = bridge->p_int_enable_64; - int_enable &= ~pcibr_int_bits; - bridge->p_int_enable_64 = int_enable; - } else { - int_enable = (uint64_t)bridge->b_int_enable; - int_enable &= ~pcibr_int_bits; - bridge->b_int_enable = (bridgereg_t)int_enable; - } - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ + pcireg_intr_enable_bit_clr(pcibr_soft, pcibr_int_bits); + pcireg_tflush_get(pcibr_soft); /* wait until Bridge PIO complete */ pcibr_unlock(pcibr_soft, s); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, @@ -654,7 +625,6 @@ for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) if (pcibr_int_bits & (1 << pcibr_int_bit)) { - void *int_addr; /* if the interrupt line is now shared, * do not disconnect it. @@ -674,19 +644,18 @@ * where the another pcibr_intr_alloc() * was in progress as we disconnected. */ + intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) continue; - intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; - if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) - continue; - - int_addr = (void *)&(bridge->p_int_addr_64[pcibr_int_bit]); - + pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit = + ((pcibr_soft->bs_busnum << 3) | pcibr_int_bit); xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr, - pcibr_intr_func, (intr_arg_t) intr_wrap, - (xtalk_intr_setfunc_t)pcibr_setpciint, - (void *)(long)pcibr_int_bit); + NULL, + (intr_arg_t) intr_wrap, + (xtalk_intr_setfunc_t) pcibr_setpciint, + &pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, "pcibr_intr_disconnect: now-sharing int_bits=0x%x\n", pcibr_int_bit)); @@ -711,10 +680,9 @@ * INTERRUPT HANDLING */ void -pcibr_clearwidint(bridge_t *bridge) +pcibr_clearwidint(pcibr_soft_t pcibr_soft) { - bridge->b_wid_int_upper = 0; - bridge->b_wid_int_lower = 0; + pcireg_intr_dst_set(pcibr_soft, 0); } @@ -724,257 +692,10 @@ xwidgetnum_t targ = xtalk_intr_target_get(intr); iopaddr_t addr = xtalk_intr_addr_get(intr); xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr); - widgetreg_t NEW_b_wid_int_upper, NEW_b_wid_int_lower; - widgetreg_t OLD_b_wid_int_upper, OLD_b_wid_int_lower; - - bridge_t *bridge = (bridge_t *)xtalk_intr_sfarg_get(intr); - - NEW_b_wid_int_upper = ( (0x000F0000 & (targ << 16)) | - XTALK_ADDR_TO_UPPER(addr)); - NEW_b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); - - OLD_b_wid_int_upper = bridge->b_wid_int_upper; - OLD_b_wid_int_lower = bridge->b_wid_int_lower; - - /* Verify that all interrupts from this Bridge are using a single PI */ - if ((OLD_b_wid_int_upper != 0) && (OLD_b_wid_int_lower != 0)) { - /* - * Once set, these registers shouldn't change; they should - * be set multiple times with the same values. - * - * If we're attempting to change these registers, it means - * that our heuristics for allocating interrupts in a way - * appropriate for IP35 have failed, and the admin needs to - * explicitly direct some interrupts (or we need to make the - * heuristics more clever). - * - * In practice, we hope this doesn't happen very often, if - * at all. - */ - if ((OLD_b_wid_int_upper != NEW_b_wid_int_upper) || - (OLD_b_wid_int_lower != NEW_b_wid_int_lower)) { - printk(KERN_WARNING "Interrupt allocation is too complex.\n"); - printk(KERN_WARNING "Use explicit administrative interrupt targetting.\n"); - printk(KERN_WARNING "bridge=0x%lx targ=0x%x\n", (unsigned long)bridge, targ); - printk(KERN_WARNING "NEW=0x%x/0x%x OLD=0x%x/0x%x\n", - NEW_b_wid_int_upper, NEW_b_wid_int_lower, - OLD_b_wid_int_upper, OLD_b_wid_int_lower); - panic("PCI Bridge interrupt targetting error\n"); - } - } - - bridge->b_wid_int_upper = NEW_b_wid_int_upper; - bridge->b_wid_int_lower = NEW_b_wid_int_lower; - bridge->b_int_host_err = vect; - -} - -/* - * pcibr_intr_preset: called during mlreset time - * if the platform specific code needs to route - * one of the Bridge's xtalk interrupts before the - * xtalk infrastructure is available. - */ -void -pcibr_xintr_preset(void *which_widget, - int which_widget_intr, - xwidgetnum_t targ, - iopaddr_t addr, - xtalk_intr_vector_t vect) -{ - bridge_t *bridge = (bridge_t *) which_widget; - - if (which_widget_intr == -1) { - /* bridge widget error interrupt */ - bridge->b_wid_int_upper = ( (0x000F0000 & (targ << 16)) | - XTALK_ADDR_TO_UPPER(addr)); - bridge->b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); - bridge->b_int_host_err = vect; -printk("pcibr_xintr_preset: b_wid_int_upper 0x%lx b_wid_int_lower 0x%lx b_int_host_err 0x%x\n", - ( (0x000F0000 & (targ << 16)) | XTALK_ADDR_TO_UPPER(addr)), - XTALK_ADDR_TO_LOWER(addr), vect); - - /* turn on all interrupts except - * the PCI interrupt requests, - * at least at heart. - */ - bridge->b_int_enable |= ~BRIDGE_IMR_INT_MSK; - - } else { - /* routing a PCI device interrupt. - * targ and low 38 bits of addr must - * be the same as the already set - * value for the widget error interrupt. - */ - bridge->b_int_addr[which_widget_intr].addr = - ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | - (BRIDGE_INT_ADDR_FLD & vect)); - /* - * now bridge can let it through; - * NB: still should be blocked at - * xtalk provider end, until the service - * function is set. - */ - bridge->b_int_enable |= 1 << vect; - } - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ -} - -/* - * pcibr_intr_func() - * - * This is the pcibr interrupt "wrapper" function that is called, - * in interrupt context, to initiate the interrupt handler(s) registered - * (via pcibr_intr_alloc/connect) for the occurring interrupt. Non-threaded - * handlers will be called directly, and threaded handlers will have their - * thread woken up. - */ -void -pcibr_intr_func(intr_arg_t arg) -{ - pcibr_intr_wrap_t wrap = (pcibr_intr_wrap_t) arg; - reg_p wrbf; - intr_func_t func; - pcibr_intr_t intr; - pcibr_intr_list_t list; - int clearit; - int do_nonthreaded = 1; - int is_threaded = 0; - int x = 0; - pcibr_soft_t pcibr_soft = wrap->iw_soft; - bridge_t *bridge = pcibr_soft->bs_base; - uint64_t p_enable = pcibr_soft->bs_int_enable; - int bit = wrap->iw_ibit; - - /* - * PIC WAR. PV#855272 - * Early attempt at a workaround for the runaway - * interrupt problem. Briefly disable the enable bit for - * this device. - */ - if (PCIBR_WAR_ENABLED(PV855272, pcibr_soft)) { - unsigned s; - - /* disable-enable interrupts for this bridge pin */ - - p_enable &= ~(1 << bit); - s = pcibr_lock(pcibr_soft); - bridge->p_int_enable_64 = p_enable; - p_enable |= (1 << bit); - bridge->p_int_enable_64 = p_enable; - pcibr_unlock(pcibr_soft, s); - } - - /* - * If any handler is still running from a previous interrupt - * just return. If there's a need to call the handler(s) again, - * another interrupt will be generated either by the device or by - * pcibr_force_interrupt(). - */ - - if (wrap->iw_hdlrcnt) { - return; - } - - /* - * Call all interrupt handlers registered. - * First, the pcibr_intrd threads for any threaded handlers will be - * awoken, then any non-threaded handlers will be called sequentially. - */ - - clearit = 1; - while (do_nonthreaded) { - for (list = wrap->iw_list; list != NULL; list = list->il_next) { - if ((intr = list->il_intr) && (intr->bi_flags & PCIIO_INTR_CONNECTED)) { + pcibr_soft_t bridge = (pcibr_soft_t)xtalk_intr_sfarg_get(intr); - - /* - * This device may have initiated write - * requests since the bridge last saw - * an edge on this interrupt input; flushing - * the buffer prior to invoking the handler - * should help but may not be sufficient if we - * get more requests after the flush, followed - * by the card deciding it wants service, before - * the interrupt handler checks to see if things need - * to be done. - * - * There is a similar race condition if - * an interrupt handler loops around and - * notices further service is requred. - * Perhaps we need to have an explicit - * call that interrupt handlers need to - * do between noticing that DMA to memory - * has completed, but before observing the - * contents of memory? - */ - - if ((do_nonthreaded) && (!is_threaded)) { - /* Non-threaded - Call the interrupt handler at interrupt level */ - /* Only need to flush write buffers if sharing */ - - if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) { - if ((x = *wrbf)) /* write request buffer flush */ -#ifdef SUPPORT_PRINTING_V_FORMAT - printk(KERN_ALERT "pcibr_intr_func %v: \n" - "write buffer flush failed, wrbf=0x%x\n", - list->il_intr->bi_dev, wrbf); -#else - printk(KERN_ALERT "pcibr_intr_func %p: \n" - "write buffer flush failed, wrbf=0x%lx\n", - (void *)list->il_intr->bi_dev, (long) wrbf); -#endif - } - func = intr->bi_func; - if ( func ) - func(intr->bi_arg); - } - clearit = 0; - } - } - do_nonthreaded = 0; - - /* - * If the non-threaded handler was the last to complete, - * (i.e., no threaded handlers still running) force an - * interrupt to avoid a potential deadlock situation. - */ - if (wrap->iw_hdlrcnt == 0) { - pcibr_force_interrupt((pcibr_intr_t) wrap); - } - } - - /* If there were no handlers, - * disable the interrupt and return. - * It will get enabled again after - * a handler is connected. - * If we don't do this, we would - * sit here and spin through the - * list forever. - */ - if (clearit) { - pcibr_soft_t pcibr_soft = wrap->iw_soft; - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t int_enable; - bridgereg_t mask = 1 << wrap->iw_ibit; - unsigned long s; - - /* PIC BRINUGP WAR (PV# 854697): - * On PIC we must write 64-bit MMRs with 64-bit stores - */ - s = pcibr_lock(pcibr_soft); - if (PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) { - int_enable = bridge->p_int_enable_64; - int_enable &= ~mask; - bridge->p_int_enable_64 = int_enable; - } else { - int_enable = (uint64_t)bridge->b_int_enable; - int_enable &= ~mask; - bridge->b_int_enable = (bridgereg_t)int_enable; - } - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); - return; - } + pcireg_intr_dst_target_id_set(bridge, targ); + pcireg_intr_dst_addr_set(bridge, addr); + pcireg_intr_host_err_set(bridge, vect); } --- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_reg.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_reg.c 2004-02-09 10:39:51.000000000 +0000 @@ -14,94 +14,867 @@ #include #include -#define IS_IOADDR(ptr) (!(((uint64_t)(ptr) & CAC_BASE) == CAC_BASE)) /* - * Control Register Access -- Read/Write 0000_0020 + * Identification Register Access -- Read Only 0000_0000 */ +static uint64_t +__pcireg_id_get(pic_t *bridge) +{ + return bridge->p_wid_id; +} uint64_t -pcireg_control_get(void *ptr) +pcireg_bridge_id_get(void *ptr) { - uint64_t ret = 0; - pic_t *bridge; + return __pcireg_id_get((pic_t *)ptr); +} - if (IS_IOADDR(ptr)) - bridge = (pic_t *) ptr; - else - bridge = (pic_t *) ((pcibr_soft_t) (ptr))->bs_base; +uint64_t +pcireg_id_get(pcibr_soft_t ptr) +{ + return __pcireg_id_get((pic_t *)ptr->bs_base); +} - ret = ((pic_t *) bridge)->p_wid_control; - return ret; + + +/* + * Address Bus Side Holding Register Access -- Read Only 0000_0010 + */ +uint64_t +pcireg_bus_err_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_wid_err; } + /* - * Interrupt Status Register Access -- Read Only 0000_0100 + * Control Register Access -- Read/Write 0000_0020 */ +static uint64_t +__pcireg_control_get(pic_t *bridge) +{ + return bridge->p_wid_control; +} + +uint64_t +pcireg_bridge_control_get(void *ptr) +{ + return __pcireg_control_get((pic_t *)ptr); +} + uint64_t -pcireg_intr_status_get(void *ptr) +pcireg_control_get(pcibr_soft_t ptr) +{ + return __pcireg_control_get((pic_t *)ptr->bs_base); +} + + +void +pcireg_control_set(pcibr_soft_t ptr, uint64_t val) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + /* WAR for PV 439897 & 454474. Add a readback of the control + * register. Lock to protect against MP accesses to this + * register along with other write-only registers (See PVs). + * This register isnt accessed in the "hot path" so the splhi + * shouldn't be a bottleneck + */ + + bridge->p_wid_control = val; + bridge->p_wid_control; /* WAR */ +} + + +void +pcireg_control_bit_clr(pcibr_soft_t ptr, uint64_t bits) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + /* WAR for PV 439897 & 454474. Add a readback of the control + * register. Lock to protect against MP accesses to this + * register along with other write-only registers (See PVs). + * This register isnt accessed in the "hot path" so the splhi + * shouldn't be a bottleneck + */ + + bridge->p_wid_control &= ~bits; + bridge->p_wid_control; /* WAR */ +} + + +void +pcireg_control_bit_set(pcibr_soft_t ptr, uint64_t bits) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + /* WAR for PV 439897 & 454474. Add a readback of the control + * register. Lock to protect against MP accesses to this + * register along with other write-only registers (See PVs). + * This register isnt accessed in the "hot path" so the splhi + * shouldn't be a bottleneck + */ + + bridge->p_wid_control |= bits; + bridge->p_wid_control; /* WAR */ +} + +/* + * Bus Speed (from control register); -- Read Only access 0000_0020 + * 0x00 == 33MHz, 0x01 == 66MHz, 0x10 == 100MHz, 0x11 == 133MHz + */ +uint64_t +pcireg_speed_get(pcibr_soft_t ptr) +{ + uint64_t speedbits; + pic_t *bridge = (pic_t *)ptr->bs_base; + + speedbits = bridge->p_wid_control & PIC_CTRL_PCI_SPEED; + return (speedbits >> 4); +} + +/* + * Bus Mode (ie. PCIX or PCI) (from Status register); 0000_0008 + * 0x0 == PCI, 0x1 == PCI-X + */ +uint64_t +pcireg_mode_get(pcibr_soft_t ptr) +{ + uint64_t pcix_active_bit; + pic_t *bridge = (pic_t *)ptr->bs_base; + + pcix_active_bit = bridge->p_wid_stat & PIC_STAT_PCIX_ACTIVE; + return (pcix_active_bit >> PIC_STAT_PCIX_ACTIVE_SHFT); +} + +void +pcireg_req_timeout_set(pcibr_soft_t ptr, uint64_t val) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_wid_req_timeout = val; +} + +/* + * Interrupt Destination Addr Register Access -- Read/Write 0000_0038 + */ + +void +pcireg_intr_dst_set(pcibr_soft_t ptr, uint64_t val) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_wid_int = val; +} + +/* + * Intr Destination Addr Reg Access (target_id) -- Read/Write 0000_0038 + */ +uint64_t +pcireg_intr_dst_target_id_get(pcibr_soft_t ptr) +{ + uint64_t tid_bits; + pic_t *bridge = (pic_t *)ptr->bs_base; + + tid_bits = (bridge->p_wid_int & PIC_INTR_DEST_TID); + return (tid_bits >> PIC_INTR_DEST_TID_SHFT); +} + +void +pcireg_intr_dst_target_id_set(pcibr_soft_t ptr, uint64_t target_id) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_wid_int &= ~PIC_INTR_DEST_TID; + bridge->p_wid_int |= + ((target_id << PIC_INTR_DEST_TID_SHFT) & PIC_INTR_DEST_TID); +} + +/* + * Intr Destination Addr Register Access (addr) -- Read/Write 0000_0038 + */ +uint64_t +pcireg_intr_dst_addr_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_wid_int & PIC_XTALK_ADDR_MASK; +} + +void +pcireg_intr_dst_addr_set(pcibr_soft_t ptr, uint64_t addr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_wid_int &= ~PIC_XTALK_ADDR_MASK; + bridge->p_wid_int |= (addr & PIC_XTALK_ADDR_MASK); +} + +/* + * Cmd Word Holding Bus Side Error Register Access -- Read Only 0000_0040 + */ +uint64_t +pcireg_cmdword_err_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_wid_err_cmdword; +} + +/* + * PCI/PCIX Target Flush Register Access -- Read Only 0000_0050 + */ +uint64_t +pcireg_tflush_get(pcibr_soft_t ptr) { - short bridge_type; - pic_t *bridge; uint64_t ret = 0; + pic_t *bridge = (pic_t *)ptr->bs_base; - if (IS_IOADDR(ptr)) - bridge = (pic_t *) ptr; - else - bridge = (pic_t *) ((pcibr_soft_t) (ptr))->bs_base; + ret = bridge->p_wid_tflush; - ret = ((pic_t *) bridge)->p_int_status; + /* Read of the Targer Flush should always return zero */ + ASSERT_ALWAYS(ret == 0); return ret; } +/* + * Cmd Word Holding Link Side Error Register Access -- Read Only 0000_0058 + */ +uint64_t +pcireg_linkside_err_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_wid_aux_err; +} + +/* + * PCI Response Buffer Address Holding Register -- Read Only 0000_0068 + */ +uint64_t +pcireg_resp_err_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_wid_resp; +} + +/* + * PCI Resp Buffer Address Holding Reg (Address) -- Read Only 0000_0068 + */ +uint64_t +pcireg_resp_err_addr_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_wid_resp & PIC_RSP_BUF_ADDR; +} + +/* + * PCI Resp Buffer Address Holding Register (Buffer)-- Read Only 0000_0068 + */ +uint64_t +pcireg_resp_err_buf_get(pcibr_soft_t ptr) +{ + uint64_t bufnum_bits; + pic_t *bridge = (pic_t *)ptr->bs_base; + + bufnum_bits = (bridge->p_wid_resp_upper & PIC_RSP_BUF_NUM); + return (bufnum_bits >> PIC_RSP_BUF_NUM_SHFT); +} + +/* + * PCI Resp Buffer Address Holding Register (Device)-- Read Only 0000_0068 + */ +uint64_t +pcireg_resp_err_dev_get(pcibr_soft_t ptr) +{ + uint64_t devnum_bits; + pic_t *bridge = (pic_t *)ptr->bs_base; + + devnum_bits = (bridge->p_wid_resp_upper & PIC_RSP_BUF_DEV_NUM); + return (devnum_bits >> PIC_RSP_BUF_DEV_NUM_SHFT); +} + +/* + * Address Holding Register Link Side Errors -- Read Only 0000_0078 + */ +uint64_t +pcireg_linkside_err_addr_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_wid_addr_lkerr; +} + +void +pcireg_dirmap_wid_set(pcibr_soft_t ptr, uint64_t target) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_dir_map &= ~PIC_DIRMAP_WID; + bridge->p_dir_map |= + ((target << PIC_DIRMAP_WID_SHFT) & PIC_DIRMAP_WID); +} + +void +pcireg_dirmap_diroff_set(pcibr_soft_t ptr, uint64_t dir_off) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_dir_map &= ~PIC_DIRMAP_DIROFF; + bridge->p_dir_map |= (dir_off & PIC_DIRMAP_DIROFF); +} + +void +pcireg_dirmap_add512_set(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_dir_map |= PIC_DIRMAP_ADD512; +} + +void +pcireg_dirmap_add512_clr(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_dir_map &= ~PIC_DIRMAP_ADD512; +} + +/* + * PCI Page Map Fault Address Register Access -- Read Only 0000_0090 + */ +uint64_t +pcireg_map_fault_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_map_fault; +} + +/* + * Arbitration Register Access -- Read/Write 0000_00A0 + */ +uint64_t +pcireg_arbitration_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_arb; +} + +void +pcireg_arbitration_bit_set(pcibr_soft_t ptr, uint64_t bits) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_arb |= bits; +} + +/* + * Internal Ram Parity Error Register Access -- Read Only 0000_00B0 + */ +uint64_t +pcireg_parity_err_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_ate_parity_err; +} + +/* + * Type 1 Configuration Register Access -- Read/Write 0000_00C8 + */ +void +pcireg_type1_cntr_set(pcibr_soft_t ptr, uint64_t val) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_pci_cfg = val; +} + +/* + * PCI Bus Error Lower Addr Holding Reg Access -- Read Only 0000_00D8 + */ +uint64_t +pcireg_pci_bus_addr_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_pci_err; +} + +/* + * PCI Bus Error Addr Holding Reg Access (Address) -- Read Only 0000_00D8 + */ +uint64_t +pcireg_pci_bus_addr_addr_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_pci_err & PIC_XTALK_ADDR_MASK; +} + +/* + * Interrupt Status Register Access -- Read Only 0000_0100 + */ +uint64_t +pcireg_intr_status_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_int_status; +} + +/* + * Interrupt Enable Register Access -- Read/Write 0000_0108 + */ +uint64_t +pcireg_intr_enable_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_int_enable; +} + +void +pcireg_intr_enable_set(pcibr_soft_t ptr, uint64_t val) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_int_enable = val; +} + void -pcireg_intr_enable_bit_clr(void *ptr, uint64_t bits) +pcireg_intr_enable_bit_clr(pcibr_soft_t ptr, uint64_t bits) { - pic_t *bridge; + pic_t *bridge = (pic_t *)ptr->bs_base; - if (IS_IOADDR(ptr)) - bridge = (pic_t *) ptr; - else - bridge = (pic_t *) ((pcibr_soft_t) (ptr))->bs_base; bridge->p_int_enable &= ~bits; } void -pcireg_intr_enable_bit_set(void *ptr, uint64_t bits) +pcireg_intr_enable_bit_set(pcibr_soft_t ptr, uint64_t bits) { - pic_t *bridge; + pic_t *bridge = (pic_t *)ptr->bs_base; - if (IS_IOADDR(ptr)) - bridge = (pic_t *) ptr; - else - bridge = (pic_t *) ((pcibr_soft_t) (ptr))->bs_base; bridge->p_int_enable |= bits; } +/* + * Interrupt Reset Register Access -- Write Only 0000_0110 + */ +void +pcireg_intr_reset_set(pcibr_soft_t ptr, uint64_t val) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_int_rst_stat = val; +} + +void +pcireg_intr_mode_set(pcibr_soft_t ptr, uint64_t val) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_int_mode = val; +} + void -pcireg_intr_addr_addr_set(void *ptr, int int_n, uint64_t addr) +pcireg_intr_device_set(pcibr_soft_t ptr, uint64_t val) { - pic_t *bridge; + pic_t *bridge = (pic_t *)ptr->bs_base; - if (IS_IOADDR(ptr)) - bridge = (pic_t *) ptr; - else - bridge = (pic_t *) ((pcibr_soft_t) (ptr))->bs_base; - bridge->p_int_addr[int_n] &= ~(0x0000FFFFFFFFFFFF); - bridge->p_int_addr[int_n] |= (addr & 0x0000FFFFFFFFFFFF); + bridge->p_int_device = val; +} + +static void +__pcireg_intr_device_bit_set(pic_t *bridge, uint64_t bits) +{ + bridge->p_int_device |= bits; +} + +void +pcireg_bridge_intr_device_bit_set(void *ptr, uint64_t bits) +{ + __pcireg_intr_device_bit_set((pic_t *)ptr, bits); +} + +void +pcireg_intr_device_bit_set(pcibr_soft_t ptr, uint64_t bits) +{ + __pcireg_intr_device_bit_set((pic_t *)ptr->bs_base, bits); +} + +void +pcireg_intr_device_bit_clr(pcibr_soft_t ptr, uint64_t bits) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_int_device &= ~bits; } /* - * Force Interrupt Register Access -- Write Only 0000_01C0 - 0000_01F8 + * Host Error Interrupt Field Register Access -- Read/Write 0000_0128 */ void -pcireg_force_intr_set(void *ptr, int int_n) +pcireg_intr_host_err_set(pcibr_soft_t ptr, uint64_t val) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_int_host_err = val; +} + +/* + * Interrupt Host Address Register -- Read/Write 0000_0130 - 0000_0168 + */ +uint64_t +pcireg_intr_addr_get(pcibr_soft_t ptr, int int_n) { - pic_t *bridge; + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_int_addr[int_n]; +} + +static void +__pcireg_intr_addr_set(pic_t *bridge, int int_n, uint64_t val) +{ + bridge->p_int_addr[int_n] = val; +} + +void +pcireg_bridge_intr_addr_set(void *ptr, int int_n, uint64_t val) +{ + __pcireg_intr_addr_set((pic_t *)ptr, int_n, val); +} + +void +pcireg_intr_addr_set(pcibr_soft_t ptr, int int_n, uint64_t val) +{ + __pcireg_intr_addr_set((pic_t *)ptr->bs_base, int_n, val); +} + +void * +pcireg_intr_addr_addr(pcibr_soft_t ptr, int int_n) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return (void *)&(bridge->p_int_addr[int_n]); +} + +static void +__pcireg_intr_addr_vect_set(pic_t *bridge, int int_n, uint64_t vect) +{ + bridge->p_int_addr[int_n] &= ~PIC_HOST_INTR_FLD; + bridge->p_int_addr[int_n] |= + ((vect << PIC_HOST_INTR_FLD_SHFT) & PIC_HOST_INTR_FLD); +} + +void +pcireg_bridge_intr_addr_vect_set(void *ptr, int int_n, uint64_t vect) +{ + __pcireg_intr_addr_vect_set((pic_t *)ptr, int_n, vect); +} + +void +pcireg_intr_addr_vect_set(pcibr_soft_t ptr, int int_n, uint64_t vect) +{ + __pcireg_intr_addr_vect_set((pic_t *)ptr->bs_base, int_n, vect); +} + + + +/* + * Intr Host Address Register (int_addr) -- Read/Write 0000_0130 - 0000_0168 + */ +static void +__pcireg_intr_addr_addr_set(pic_t *bridge, int int_n, uint64_t addr) +{ + bridge->p_int_addr[int_n] &= ~PIC_HOST_INTR_ADDR; + bridge->p_int_addr[int_n] |= (addr & PIC_HOST_INTR_ADDR); +} + +void +pcireg_bridge_intr_addr_addr_set(void *ptr, int int_n, uint64_t addr) +{ + __pcireg_intr_addr_addr_set((pic_t *)ptr, int_n, addr); +} + +void +pcireg_intr_addr_addr_set(pcibr_soft_t ptr, int int_n, uint64_t addr) +{ + __pcireg_intr_addr_addr_set((pic_t *)ptr->bs_base, int_n, addr); +} + +/* + * Multiple Interrupt Register Access -- Read Only 0000_0178 + */ +uint64_t +pcireg_intr_multiple_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_mult_int; +} + +/* + * Force Always Intr Register Access -- Write Only 0000_0180 - 0000_01B8 + */ +static void * +__pcireg_force_always_addr_get(pic_t *bridge, int int_n) +{ + return (void *)&(bridge->p_force_always[int_n]); +} + +void * +pcireg_bridge_force_always_addr_get(void *ptr, int int_n) +{ + return __pcireg_force_always_addr_get((pic_t *)ptr, int_n); +} + +void * +pcireg_force_always_addr_get(pcibr_soft_t ptr, int int_n) +{ + return __pcireg_force_always_addr_get((pic_t *)ptr->bs_base, int_n); +} + +/* + * Force Interrupt Register Access -- Write Only 0000_01C0 - 0000_01F8 + */ +void +pcireg_force_intr_set(pcibr_soft_t ptr, int int_n) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; - if (IS_IOADDR(ptr)) - bridge = (pic_t *) ptr; - else - bridge = (pic_t *) ((pcibr_soft_t) (ptr))->bs_base; bridge->p_force_pin[int_n] = 1; } + +/* + * Device(x) Register Access -- Read/Write 0000_0200 - 0000_0218 + */ +uint64_t +pcireg_device_get(pcibr_soft_t ptr, int device) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + ASSERT_ALWAYS((device >= 0) && (device <= 3)); + return bridge->p_device[device]; +} + +void +pcireg_device_set(pcibr_soft_t ptr, int device, uint64_t val) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + ASSERT_ALWAYS((device >= 0) && (device <= 3)); + bridge->p_device[device] = val; +} + +/* + * Device(x) Write Buffer Flush Reg Access -- Read Only 0000_0240 - 0000_0258 + */ +uint64_t +pcireg_wrb_flush_get(pcibr_soft_t ptr, int device) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + uint64_t ret = 0; + + ASSERT_ALWAYS((device >= 0) && (device <= 3)); + ret = bridge->p_wr_req_buf[device]; + + /* Read of the Write Buffer Flush should always return zero */ + ASSERT_ALWAYS(ret == 0); + return ret; +} + +/* + * Even/Odd RRB Register Access -- Read/Write 0000_0280 - 0000_0288 + */ +uint64_t +pcireg_rrb_get(pcibr_soft_t ptr, int even_odd) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_rrb_map[even_odd]; +} + +void +pcireg_rrb_set(pcibr_soft_t ptr, int even_odd, uint64_t val) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_rrb_map[even_odd] = val; +} + +void +pcireg_rrb_bit_set(pcibr_soft_t ptr, int even_odd, uint64_t bits) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_rrb_map[even_odd] |= bits; +} + +/* + * RRB Status Register Access -- Read Only 0000_0290 + */ +uint64_t +pcireg_rrb_status_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_resp_status; +} + +/* + * RRB Clear Register Access -- Write Only 0000_0298 + */ +void +pcireg_rrb_clear_set(pcibr_soft_t ptr, uint64_t val) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + bridge->p_resp_clear = val; +} + +/* + * PCIX Bus Error Address Register Access -- Read Only 0000_0600 + */ +uint64_t +pcireg_pcix_bus_err_addr_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_pcix_bus_err_addr; +} + +/* + * PCIX Bus Error Attribute Register Access -- Read Only 0000_0608 + */ +uint64_t +pcireg_pcix_bus_err_attr_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_pcix_bus_err_attr; +} + +/* + * PCIX Bus Error Data Register Access -- Read Only 0000_0610 + */ +uint64_t +pcireg_pcix_bus_err_data_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_pcix_bus_err_data; +} + +/* + * PCIX PIO Split Request Address Register Access -- Read Only 0000_0618 + */ +uint64_t +pcireg_pcix_pio_split_addr_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_pcix_pio_split_addr; +} + +/* + * PCIX PIO Split Request Attribute Register Access -- Read Only 0000_0620 + */ +uint64_t +pcireg_pcix_pio_split_attr_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_pcix_pio_split_attr; +} + +/* + * PCIX DMA Request Error Attribute Register Access -- Read Only 0000_0628 + */ +uint64_t +pcireg_pcix_req_err_attr_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_pcix_dma_req_err_attr; +} + +/* + * PCIX DMA Request Error Address Register Access -- Read Only 0000_0630 + */ +uint64_t +pcireg_pcix_req_err_addr_get(pcibr_soft_t ptr) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + return bridge->p_pcix_dma_req_err_addr; +} + +/* + * Type 0 Configuration Space Access -- Read/Write + */ +cfg_p +pcireg_type0_cfg_addr(pcibr_soft_t ptr, uint8_t slot, uint8_t func, int off) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + /* Type 0 Config space accesses on PIC are 1-4, not 0-3 since + * it is a PCIX Bridge. See sys/PCI/pic.h for explanation. + */ + slot++; + ASSERT_ALWAYS(((int) slot >= 1) && ((int) slot <= 4)); + return &(bridge->p_type0_cfg_dev[slot].f[func].l[(off / 4)]); +} + +/* + * Type 1 Configuration Space Access -- Read/Write + */ +cfg_p +pcireg_type1_cfg_addr(pcibr_soft_t ptr, uint8_t func, int offset) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + /* + * Return a config space address for the given slot/func/offset. + * Note the returned ptr is a 32bit word (ie. cfg_p) aligned ptr + * pointing to the 32bit word that contains the "offset" byte. + */ + return &(bridge->p_type1_cfg.f[func].l[(offset / 4)]); +} + +/* + * Internal ATE SSRAM Access -- Read/Write + */ +bridge_ate_t +pcireg_int_ate_get(pcibr_soft_t ptr, int ate_index) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + ASSERT_ALWAYS((ate_index >= 0) && (ate_index <= 1024)); + return bridge->p_int_ate_ram[ate_index]; +} + +void +pcireg_int_ate_set(pcibr_soft_t ptr, int ate_index, bridge_ate_t val) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + ASSERT_ALWAYS((ate_index >= 0) && (ate_index <= 1024)); + bridge->p_int_ate_ram[ate_index] = (picate_t) val; +} + +bridge_ate_p +pcireg_int_ate_addr(pcibr_soft_t ptr, int ate_index) +{ + pic_t *bridge = (pic_t *)ptr->bs_base; + + ASSERT_ALWAYS((ate_index >= 0) && (ate_index <= 1024)); + return &(bridge->p_int_ate_ram[ate_index]); +} --- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c 2004-02-09 10:39:51.000000000 +0000 @@ -14,23 +14,19 @@ #include #include -void do_pcibr_rrb_clear(bridge_t *, int); -void do_pcibr_rrb_flush(bridge_t *, int); -int do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t, int); -int do_pcibr_rrb_count_avail(bridge_t *, pciio_slot_t); -int do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int, int); -int do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int, int); -void do_pcibr_rrb_free_all(pcibr_soft_t, bridge_t *, pciio_slot_t); - -void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int); - -int pcibr_wrb_flush(vertex_hdl_t); -int pcibr_rrb_alloc(vertex_hdl_t, int *, int *); -int pcibr_rrb_check(vertex_hdl_t, int *, int *, int *, int *); -void pcibr_rrb_flush(vertex_hdl_t); -int pcibr_slot_initial_rrb_alloc(vertex_hdl_t,pciio_slot_t); +void pcibr_rrb_alloc_init(pcibr_soft_t, int, int, int); +void pcibr_rrb_alloc_more(pcibr_soft_t, int, int, int); + +int pcibr_wrb_flush(vertex_hdl_t); +int pcibr_rrb_alloc(vertex_hdl_t, int *, int *); +int pcibr_rrb_check(vertex_hdl_t, int *, int *, int *, int *); +int pcibr_alloc_all_rrbs(vertex_hdl_t, int, int, int, int, + int, int, int, int, int); +void pcibr_rrb_flush(vertex_hdl_t); +int pcibr_slot_initial_rrb_alloc(vertex_hdl_t,pciio_slot_t); + +void pcibr_rrb_debug(char *, pcibr_soft_t); -void pcibr_rrb_debug(char *, pcibr_soft_t); /* * RRB Management @@ -52,23 +48,27 @@ #define RRB_MASK (0xf) /* mask a single rrb within reg */ #define RRB_SIZE (4) /* sizeof rrb within reg (bits) */ -#define RRB_ENABLE_BIT(bridge) (0x8) /* [BRIDGE | PIC]_RRB_EN */ -#define NUM_PDEV_BITS(bridge) (1) -#define NUM_VDEV_BITS(bridge) (2) -#define NUMBER_VCHANNELS(bridge) (4) -#define SLOT_2_PDEV(bridge, slot) ((slot) >> 1) -#define SLOT_2_RRB_REG(bridge, slot) ((slot) & 0x1) - -/* validate that the slot and virtual channel are valid for a given bridge */ -#define VALIDATE_SLOT_n_VCHAN(bridge, s, v) \ - (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)3)) && (((v) >= 0) && ((v) <= 3))) ? 1 : 0) +#define RRB_ENABLE_BIT (0x8) /* [BRIDGE | PIC]_RRB_EN */ +#define NUM_PDEV_BITS (1) +#define NUMBER_VCHANNELS (4) +#define SLOT_2_PDEV(slot) ((slot) >> 1) +#define SLOT_2_RRB_REG(slot) ((slot) & 0x1) + +#define RRB_VALID(rrb) (0x00010000 << (rrb)) +#define RRB_INUSE(rrb) (0x00000001 << (rrb)) +#define RRB_CLEAR(rrb) (0x00000001 << (rrb)) + +/* validate that the slot and virtual channel are valid */ +#define VALIDATE_SLOT_n_VCHAN(s, v) \ + (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)3)) && \ + (((v) >= 0) && ((v) <= 3))) ? 1 : 0) /* * Count how many RRBs are marked valid for the specified PCI slot * and virtual channel. Return the count. */ -int -do_pcibr_rrb_count_valid(bridge_t *bridge, +static int +do_pcibr_rrb_count_valid(pcibr_soft_t pcibr_soft, pciio_slot_t slot, int vchan) { @@ -76,18 +76,18 @@ uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits; int rrb_index, cnt=0; - if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) { + if (!VALIDATE_SLOT_n_VCHAN(slot, vchan)) { printk(KERN_WARNING "do_pcibr_rrb_count_valid() invalid slot/vchan [%d/%d]\n", slot, vchan); return 0; } - enable_bit = RRB_ENABLE_BIT(bridge); - vchan_bits = vchan << NUM_PDEV_BITS(bridge); - pdev_bits = SLOT_2_PDEV(bridge, slot); + enable_bit = RRB_ENABLE_BIT; + vchan_bits = vchan << NUM_PDEV_BITS; + pdev_bits = SLOT_2_PDEV(slot); rrb_bits = enable_bit | vchan_bits | pdev_bits; - tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - + tmp = pcireg_rrb_get(pcibr_soft, SLOT_2_RRB_REG(slot)); + for (rrb_index = 0; rrb_index < 8; rrb_index++) { if ((tmp & RRB_MASK) == rrb_bits) cnt++; @@ -101,23 +101,23 @@ * Count how many RRBs are available to be allocated to the specified * slot. Return the count. */ -int -do_pcibr_rrb_count_avail(bridge_t *bridge, +static int +do_pcibr_rrb_count_avail(pcibr_soft_t pcibr_soft, pciio_slot_t slot) { uint64_t tmp; uint16_t enable_bit; int rrb_index, cnt=0; - if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, 0)) { + if (!VALIDATE_SLOT_n_VCHAN(slot, 0)) { printk(KERN_WARNING "do_pcibr_rrb_count_avail() invalid slot/vchan"); return 0; } - enable_bit = RRB_ENABLE_BIT(bridge); - - tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - + enable_bit = RRB_ENABLE_BIT; + + tmp = pcireg_rrb_get(pcibr_soft, SLOT_2_RRB_REG(slot)); + for (rrb_index = 0; rrb_index < 8; rrb_index++) { if ((tmp & enable_bit) != enable_bit) cnt++; @@ -135,8 +135,8 @@ * Note that if a request can be partially filled, it will be, even if * we return failure. */ -int -do_pcibr_rrb_alloc(bridge_t *bridge, +static int +do_pcibr_rrb_alloc(pcibr_soft_t pcibr_soft, pciio_slot_t slot, int vchan, int more) @@ -145,18 +145,18 @@ uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits; int rrb_index; - if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) { + if (!VALIDATE_SLOT_n_VCHAN(slot, vchan)) { printk(KERN_WARNING "do_pcibr_rrb_alloc() invalid slot/vchan"); return -1; } - enable_bit = RRB_ENABLE_BIT(bridge); - vchan_bits = vchan << NUM_PDEV_BITS(bridge); - pdev_bits = SLOT_2_PDEV(bridge, slot); + enable_bit = RRB_ENABLE_BIT; + vchan_bits = vchan << NUM_PDEV_BITS; + pdev_bits = SLOT_2_PDEV(slot); rrb_bits = enable_bit | vchan_bits | pdev_bits; - - reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - + + reg = tmp = pcireg_rrb_get(pcibr_soft, SLOT_2_RRB_REG(slot)); + for (rrb_index = 0; ((rrb_index < 8) && (more > 0)); rrb_index++) { if ((tmp & enable_bit) != enable_bit) { /* clear the rrb and OR in the new rrb into 'reg' */ @@ -166,11 +166,41 @@ } tmp = (tmp >> RRB_SIZE); } - - bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; + + pcireg_rrb_set(pcibr_soft, SLOT_2_RRB_REG(slot), reg); return (more ? -1 : 0); } +/* + * Wait for the the specified rrb to have no outstanding XIO pkts + * and for all data to be drained. Mark the rrb as no longer being + * valid. + */ +static void +do_pcibr_rrb_clear(pcibr_soft_t pcibr_soft, int rrb) +{ + uint64_t status; + + /* bridge_lock must be held; this RRB must be disabled. */ + + /* wait until RRB has no outstanduing XIO packets. */ + status = pcireg_rrb_status_get(pcibr_soft); + while (status & RRB_INUSE(rrb)) { + status = pcireg_rrb_status_get(pcibr_soft); + } + + /* if the RRB has data, drain it. */ + if (status & RRB_VALID(rrb)) { + pcireg_rrb_clear_set(pcibr_soft, RRB_CLEAR(rrb)); + + /* wait until RRB is no longer valid. */ + status = pcireg_rrb_status_get(pcibr_soft); + while (status & RRB_VALID(rrb)) { + status = pcireg_rrb_status_get(pcibr_soft); + } + } +} + /* * Release some of the RRBs that have been allocated for the specified @@ -180,8 +210,8 @@ * Note that if a request can be partially fulfilled, it will be, even * if we return failure. */ -int -do_pcibr_rrb_free(bridge_t *bridge, +static int +do_pcibr_rrb_free(pcibr_soft_t pcibr_soft, pciio_slot_t slot, int vchan, int less) @@ -190,18 +220,18 @@ uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits; int rrb_index; - if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) { + if (!VALIDATE_SLOT_n_VCHAN(slot, vchan)) { printk(KERN_WARNING "do_pcibr_rrb_free() invalid slot/vchan"); return -1; } - enable_bit = RRB_ENABLE_BIT(bridge); - vchan_bits = vchan << NUM_PDEV_BITS(bridge); - pdev_bits = SLOT_2_PDEV(bridge, slot); + enable_bit = RRB_ENABLE_BIT; + vchan_bits = vchan << NUM_PDEV_BITS; + pdev_bits = SLOT_2_PDEV(slot); rrb_bits = enable_bit | vchan_bits | pdev_bits; - - reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - + + reg = tmp = pcireg_rrb_get(pcibr_soft, SLOT_2_RRB_REG(slot)); + for (rrb_index = 0; ((rrb_index < 8) && (less > 0)); rrb_index++) { if ((tmp & RRB_MASK) == rrb_bits) { /* @@ -210,132 +240,144 @@ * reg = reg & ~(RRB_MASK << (RRB_SIZE * rrb_index)); * But to be compatible with old code we'll only clear enable. */ - reg = reg & ~(RRB_ENABLE_BIT(bridge) << (RRB_SIZE * rrb_index)); + reg = reg & ~(RRB_ENABLE_BIT << (RRB_SIZE * rrb_index)); clr = clr | (enable_bit << (RRB_SIZE * rrb_index)); less--; } tmp = (tmp >> RRB_SIZE); } - - bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; - + + pcireg_rrb_set(pcibr_soft, SLOT_2_RRB_REG(slot), reg); + /* call do_pcibr_rrb_clear() for all the rrbs we've freed */ for (rrb_index = 0; rrb_index < 8; rrb_index++) { - int evn_odd = SLOT_2_RRB_REG(bridge, slot); + int evn_odd = SLOT_2_RRB_REG(slot); if (clr & (enable_bit << (RRB_SIZE * rrb_index))) - do_pcibr_rrb_clear(bridge, (2 * rrb_index) + evn_odd); + do_pcibr_rrb_clear(pcibr_soft, (2 * rrb_index) + evn_odd); } return (less ? -1 : 0); } - +/* + * Flush the specified rrb by calling do_pcibr_rrb_clear(). This + * routine is just a wrapper to make sure the rrb is disabled + * before calling do_pcibr_rrb_clear(). + */ +static void +do_pcibr_rrb_flush(pcibr_soft_t pcibr_soft, int rrbn) +{ + uint64_t rrbv; + int shft = (RRB_SIZE * (rrbn >> 1)); + uint64_t ebit = RRB_ENABLE_BIT << shft; + + rrbv = pcireg_rrb_get(pcibr_soft, (rrbn & 1)); + if (rrbv & ebit) { + pcireg_rrb_set(pcibr_soft, (rrbn & 1), (rrbv & ~ebit)); + } + + do_pcibr_rrb_clear(pcibr_soft, rrbn); + + if (rrbv & ebit) { + pcireg_rrb_set(pcibr_soft, (rrbn & 1), rrbv); + } +} + /* * free all the rrbs (both the normal and virtual channels) for the * specified slot. */ void do_pcibr_rrb_free_all(pcibr_soft_t pcibr_soft, - bridge_t *bridge, pciio_slot_t slot) { int vchan; - int vchan_total = NUMBER_VCHANNELS(bridge); + int vchan_total = NUMBER_VCHANNELS; /* pretend we own all 8 rrbs and just ignore the return value */ for (vchan = 0; vchan < vchan_total; vchan++) { - (void)do_pcibr_rrb_free(bridge, slot, vchan, 8); + do_pcibr_rrb_free(pcibr_soft, slot, vchan, 8); pcibr_soft->bs_rrb_valid[slot][vchan] = 0; } } - - + + /* - * Wait for the the specified rrb to have no outstanding XIO pkts - * and for all data to be drained. Mark the rrb as no longer being - * valid. + * Initialize a slot with a given number of RRBs. (this routine + * will also give back RRBs if the slot has more than we want). */ void -do_pcibr_rrb_clear(bridge_t *bridge, int rrb) -{ - uint64_t status; +pcibr_rrb_alloc_init(pcibr_soft_t pcibr_soft, + int slot, + int vchan, + int init_rrbs) +{ + int had = pcibr_soft->bs_rrb_valid[slot][vchan]; + int have = had; + int added = 0; - /* bridge_lock must be held; - * this RRB must be disabled. - */ - - /* wait until RRB has no outstanduing XIO packets. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - - /* if the RRB has data, drain it. */ - if (status & BRIDGE_RRB_VALID(rrb)) { - bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); + for (added = 0; have < init_rrbs; ++added, ++have) { + if (pcibr_soft->bs_rrb_res[slot] > 0) + pcibr_soft->bs_rrb_res[slot]--; + else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0) + pcibr_soft->bs_rrb_avail[slot & 1]--; + else + break; + if (do_pcibr_rrb_alloc(pcibr_soft, slot, vchan, 1) < 0) + break; - /* wait until RRB is no longer valid. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } + pcibr_soft->bs_rrb_valid[slot][vchan]++; } -} - - -/* - * Flush the specified rrb by calling do_pcibr_rrb_clear(). This - * routine is just a wrapper to make sure the rrb is disabled - * before calling do_pcibr_rrb_clear(). - */ -void -do_pcibr_rrb_flush(bridge_t *bridge, int rrbn) -{ - reg_p rrbp = &bridge->b_rrb_map[rrbn & 1].reg; - bridgereg_t rrbv; - int shft = (RRB_SIZE * (rrbn >> 1)); - unsigned long ebit = RRB_ENABLE_BIT(bridge) << shft; - rrbv = *rrbp; - - if (rrbv & ebit) { - *rrbp = rrbv & ~ebit; + /* Free any extra RRBs that the slot may have allocated to it */ + while (have > init_rrbs) { + pcibr_soft->bs_rrb_avail[slot & 1]++; + pcibr_soft->bs_rrb_valid[slot][vchan]--; + do_pcibr_rrb_free(pcibr_soft, slot, vchan, 1); + added--; + have--; } - do_pcibr_rrb_clear(bridge, rrbn); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, + "pcibr_rrb_alloc_init: had %d, added/removed %d, " + "(of requested %d) RRBs " + "to slot %d, vchan %d\n", had, added, init_rrbs, + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vchan)); - if (rrbv & ebit) { - *rrbp = rrbv; - } + pcibr_rrb_debug("pcibr_rrb_alloc_init", pcibr_soft); } +/* + * Allocate more RRBs to a given slot (if the RRBs are available). + */ void -do_pcibr_rrb_autoalloc(pcibr_soft_t pcibr_soft, - int slot, - int vchan, - int more_rrbs) +pcibr_rrb_alloc_more(pcibr_soft_t pcibr_soft, + int slot, + int vchan, + int more_rrbs) { - bridge_t *bridge = pcibr_soft->bs_base; - int got; + int added; - for (got = 0; got < more_rrbs; ++got) { + for (added = 0; added < more_rrbs; ++added) { if (pcibr_soft->bs_rrb_res[slot] > 0) pcibr_soft->bs_rrb_res[slot]--; else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0) pcibr_soft->bs_rrb_avail[slot & 1]--; else break; - if (do_pcibr_rrb_alloc(bridge, slot, vchan, 1) < 0) + if (do_pcibr_rrb_alloc(pcibr_soft, slot, vchan, 1) < 0) break; pcibr_soft->bs_rrb_valid[slot][vchan]++; } PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, - "do_pcibr_rrb_autoalloc: added %d (of %d requested) RRBs " - "to slot %d, vchan %d\n", got, more_rrbs, + "pcibr_rrb_alloc_more: added %d (of %d requested) RRBs " + "to slot %d, vchan %d\n", added, more_rrbs, PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vchan)); - pcibr_rrb_debug("do_pcibr_rrb_autoalloc", pcibr_soft); + pcibr_rrb_debug("pcibr_rrb_alloc_more", pcibr_soft); } @@ -348,25 +390,24 @@ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t)pciio_info_mfast_get(pciio_info); pciio_slot_t slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; uint64_t tmp; uint16_t enable_bit, pdev_bits, rrb_bits, rrb_mask; int rrb_index; unsigned long s; - enable_bit = RRB_ENABLE_BIT(bridge); - pdev_bits = SLOT_2_PDEV(bridge, slot); + enable_bit = RRB_ENABLE_BIT; + pdev_bits = SLOT_2_PDEV(slot); rrb_bits = enable_bit | pdev_bits; - rrb_mask = enable_bit | ((NUM_PDEV_BITS(bridge) << 1) - 1); + rrb_mask = enable_bit | ((NUM_PDEV_BITS << 1) - 1); - tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; + tmp = pcireg_rrb_get(pcibr_soft, SLOT_2_RRB_REG(slot)); s = pcibr_lock(pcibr_soft); for (rrb_index = 0; rrb_index < 8; rrb_index++) { - int evn_odd = SLOT_2_RRB_REG(bridge, slot); + int evn_odd = SLOT_2_RRB_REG(slot); if ((tmp & rrb_mask) == rrb_bits) - do_pcibr_rrb_flush(bridge, (2 * rrb_index) + evn_odd); + do_pcibr_rrb_flush(pcibr_soft, (2 * rrb_index) + evn_odd); tmp = (tmp >> RRB_SIZE); } pcibr_unlock(pcibr_soft, s); @@ -383,13 +424,10 @@ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - volatile bridgereg_t *wrb_flush; - wrb_flush = &(bridge->b_wr_req_buf[pciio_slot].reg); - while (*wrb_flush) - ; - return(0); + pcireg_wrb_flush_get(pcibr_soft, pciio_slot); + + return 0; } /* @@ -411,7 +449,6 @@ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; int desired_vchan0; int desired_vchan1; int orig_vchan0; @@ -441,7 +478,7 @@ s = pcibr_lock(pcibr_soft); - vchan_total = NUMBER_VCHANNELS(bridge); + vchan_total = NUMBER_VCHANNELS; /* Save the boot-time RRB configuration for this slot */ if (pcibr_soft->bs_rrb_valid_dflt[pciio_slot][VCHAN0] < 0) { @@ -507,14 +544,14 @@ /* Commit the allocations: free, then alloc. */ if (delta_vchan0 < 0) - (void) do_pcibr_rrb_free(bridge, pciio_slot, VCHAN0, -delta_vchan0); + do_pcibr_rrb_free(pcibr_soft, pciio_slot, VCHAN0, -delta_vchan0); if (delta_vchan1 < 0) - (void) do_pcibr_rrb_free(bridge, pciio_slot, VCHAN1, -delta_vchan1); + do_pcibr_rrb_free(pcibr_soft, pciio_slot, VCHAN1, -delta_vchan1); if (delta_vchan0 > 0) - (void) do_pcibr_rrb_alloc(bridge, pciio_slot, VCHAN0, delta_vchan0); + do_pcibr_rrb_alloc(pcibr_soft, pciio_slot, VCHAN0, delta_vchan0); if (delta_vchan1 > 0) - (void) do_pcibr_rrb_alloc(bridge, pciio_slot, VCHAN1, delta_vchan1); + do_pcibr_rrb_alloc(pcibr_soft, pciio_slot, VCHAN1, delta_vchan1); /* Return final values to caller. */ @@ -666,7 +703,6 @@ pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; - bridge_t *bridge; int vchan_total; int vchan; int chan[4]; @@ -674,17 +710,15 @@ pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) - return(-EINVAL); + return -EINVAL; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(-EINVAL); - - bridge = pcibr_soft->bs_base; + return -EINVAL; /* How many RRBs are on this slot? */ - vchan_total = NUMBER_VCHANNELS(bridge); + vchan_total = NUMBER_VCHANNELS; for (vchan = 0; vchan < vchan_total; vchan++) - chan[vchan] = do_pcibr_rrb_count_valid(bridge, slot, vchan); + chan[vchan] = do_pcibr_rrb_count_valid(pcibr_soft, slot, vchan); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_vhdl, "pcibr_slot_initial_rrb_alloc: slot %d started with %d+%d+%d+%d\n", @@ -695,44 +729,44 @@ */ pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; pcibr_info = pcibr_infoh[0]; + /* + * PIC BRINGUP WAR (PV# 856866, 859504, 861476, 861478): + * Don't free RRBs we allocated to device[2|3]--vchan3 as + * a WAR to those PVs mentioned above. In pcibr_attach2 + * we allocate RRB0,8,1,9 to device[2|3]--vchan3. + */ + if (PCIBR_WAR_ENABLED(PV856866, pcibr_soft) && + (slot == 2 || slot == 3) && + (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && + !pcibr_soft->bs_slot[slot].has_host) { - if (PCIBR_WAR_ENABLED(PV856866, pcibr_soft) && - (slot == 2 || slot == 3) && - (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && - !pcibr_soft->bs_slot[slot].has_host) { - - for (vchan = 0; vchan < 2; vchan++) { - do_pcibr_rrb_free(bridge, slot, vchan, 8); - pcibr_soft->bs_rrb_valid[slot][vchan] = 0; - } + for (vchan = 0; vchan < 2; vchan++) { + do_pcibr_rrb_free(pcibr_soft, slot, vchan, 8); + pcibr_soft->bs_rrb_valid[slot][vchan] = 0; + } pcibr_soft->bs_rrb_valid[slot][3] = chan[3]; - return(-ENODEV); + return -ENODEV; } - /* Give back any assigned to empty slots */ - if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && !pcibr_soft->bs_slot[slot].has_host) { - do_pcibr_rrb_free_all(pcibr_soft, bridge, slot); - return(-ENODEV); + if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && + !pcibr_soft->bs_slot[slot].has_host) { + do_pcibr_rrb_free_all(pcibr_soft, slot); + + /* Reserve RRBs for this empty slot for hot-plug */ + for (vchan = 0; vchan < vchan_total; vchan++) + pcibr_soft->bs_rrb_valid[slot][vchan] = 0; + + return -ENODEV; } for (vchan = 0; vchan < vchan_total; vchan++) pcibr_soft->bs_rrb_valid[slot][vchan] = chan[vchan]; - return(0); + return 0; } -void -rrb_reserved_free(pcibr_soft_t pcibr_soft, int slot) -{ - int res = pcibr_soft->bs_rrb_res[slot]; - - if (res) { - pcibr_soft->bs_rrb_avail[slot & 1] += res; - pcibr_soft->bs_rrb_res[slot] = 0; - } -} /* * pcibr_initial_rrb @@ -750,7 +784,6 @@ pciio_slot_t first, pciio_slot_t last) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; pciio_slot_t slot; int rrb_total; int vchan_total; @@ -763,12 +796,12 @@ have[1][0] = have[1][1] = have[1][2] = 0; res[0] = res[1] = 0; - vchan_total = NUMBER_VCHANNELS(bridge); + vchan_total = NUMBER_VCHANNELS; for (slot = pcibr_soft->bs_min_slot; slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { /* Initial RRB management; give back RRBs in all non-existent slots */ - (void) pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot); + pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot); /* Base calculations only on existing slots */ if ((slot >= first) && (slot <= last)) { @@ -782,8 +815,8 @@ } /* Initialize even/odd slot available RRB counts */ - pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(bridge, 0); - pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(bridge, 1); + pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(pcibr_soft, 0); + pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(pcibr_soft, 1); /* * Calculate reserved RRBs for slots based on current RRB usage @@ -804,6 +837,9 @@ for (slot = first; slot <= last; ++slot) { int r; + if (pcibr_soft->bs_unused_slot & (1 << slot)) + continue; + rrb_total = 0; for (vchan = 0; vchan < vchan_total; vchan++) rrb_total += pcibr_soft->bs_rrb_valid[slot][vchan]; @@ -829,7 +865,6 @@ pcibr_rrb_debug(char *calling_func, pcibr_soft_t pcibr_soft) { pciio_slot_t slot; - char tmp_str[256]; if (pcibr_debug_mask & PCIBR_DEBUG_RRB) { PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, @@ -837,23 +872,17 @@ pcibr_soft->bs_rrb_avail[0], pcibr_soft->bs_rrb_avail[1])); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, - "\tslot\tvchan0\tvchan1\tvchan2\tvchan3\treserved\n")); + "\tslot\tvchan0\tvchan1\tvchan2\tvchan3\treserved\n")); for (slot=0; slot < PCIBR_NUM_SLOTS(pcibr_soft); slot++) { - /* - * The kernel only allows functions to have so many variable args, - * attempting to call PCIBR_DEBUG_ALWAYS() with more than 5 printf - * arguments fails so sprintf() it into a temporary string. - */ - sprintf(tmp_str, "\t %d\t %d\t %d\t %d\t %d\t %d\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), - 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN0], - 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN1], - 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN2], - 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN3], - pcibr_soft->bs_rrb_res[slot]); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, - "%s", tmp_str)); + "\t %d\t %d\t %d\t %d\t %d\t %d\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), + 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN0], + 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN1], + 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN2], + 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN3], + pcibr_soft->bs_rrb_res[slot])); } } } --- diff/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c 2004-02-09 10:39:51.000000000 +0000 @@ -37,11 +37,12 @@ pciio_slot_t slot, int drv_flags); int pcibr_slot_detach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags, char *l1_msg, int *sub_errorp); -static int pcibr_probe_slot(bridge_t *, cfg_p, unsigned int *); +static int pcibr_probe_slot(pcibr_soft_t, cfg_p, unsigned int *); +static int pcibr_probe_work(pcibr_soft_t pcibr_soft, void *addr, int len, void *valp); void pcibr_device_info_free(vertex_hdl_t, pciio_slot_t); iopaddr_t pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t, pciio_space_t, int, int, int); -void pciibr_bus_addr_free(pcibr_soft_t, pciio_win_info_t); +void pcibr_bus_addr_free(pciio_win_info_t); cfg_p pcibr_find_capability(cfg_p, unsigned); extern uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); @@ -57,22 +58,6 @@ int max_splittrans_to_numbuf[MAX_SPLIT_TABLE] = {1, 2, 3, 4, 8, 12, 16, 32}; int max_readcount_to_bufsize[MAX_READCNT_TABLE] = {512, 1024, 2048, 4096 }; -char *pci_space_name[] = {"NONE", - "ROM", - "IO", - "", - "MEM", - "MEM32", - "MEM64", - "CFG", - "WIN0", - "WIN1", - "WIN2", - "WIN3", - "WIN4", - "WIN5", - "", - "BAD"}; /* * pcibr_slot_info_init @@ -87,7 +72,6 @@ pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; - bridge_t *bridge; cfg_p cfgw; unsigned idword; unsigned pfail; @@ -106,28 +90,28 @@ int func; vertex_hdl_t conn_vhdl; pcibr_soft_slot_t slotp; - + uint64_t device_reg; + /* Get the basic software information required to proceed */ pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) - return(EINVAL); + return -EINVAL; - bridge = pcibr_soft->bs_base; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(EINVAL); + return -EINVAL; /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization * is done by the host slot then we are done. */ if (pcibr_soft->bs_slot[slot].has_host) { - return(0); + return 0; } /* Try to read the device-id/vendor-id from the config space */ - cfgw = pcibr_slot_config_addr(bridge, slot, 0); + cfgw = pcibr_slot_config_addr(pcibr_soft, slot, 0); - if (pcibr_probe_slot(bridge, cfgw, &idword)) - return(ENODEV); + if (pcibr_probe_slot(pcibr_soft, cfgw, &idword)) + return -ENODEV; slotp = &pcibr_soft->bs_slot[slot]; slotp->slot_status |= SLOT_POWER_UP; @@ -143,7 +127,7 @@ * and we are done. */ if (vendor == 0xFFFF) - return(ENODEV); + return -ENODEV; htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); nfunc = 1; @@ -157,8 +141,8 @@ if (htype & 0x80) { /* MULTIFUNCTION */ for (func = 1; func < 8; ++func) { - cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); - if (pcibr_probe_slot(bridge, cfgw, &idwords[func])) { + cfgw = pcibr_func_config_addr(pcibr_soft, 0, slot, func, 0); + if (pcibr_probe_slot(pcibr_soft, cfgw, &idwords[func])) { pfail |= 1 << func; continue; } @@ -170,11 +154,11 @@ nfunc = func + 1; rfunc = 0; } - cfgw = pcibr_slot_config_addr(bridge, slot, 0); + cfgw = pcibr_slot_config_addr(pcibr_soft, slot, 0); } pcibr_infoh = kmalloc(nfunc*sizeof (*(pcibr_infoh)), GFP_KERNEL); if ( !pcibr_infoh ) { - return ENOMEM; + return -ENOMEM; } memset(pcibr_infoh, 0, nfunc*sizeof (*(pcibr_infoh))); @@ -189,7 +173,7 @@ continue; idword = idwords[func]; - cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); + cfgw = pcibr_func_config_addr(pcibr_soft, 0, slot, func, 0); device = 0xFFFF & (idword >> 16); htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); @@ -223,9 +207,8 @@ */ lt_time = do_pcibr_config_get(cfgw, PCI_CFG_LATENCY_TIMER, 1); - - if ((lt_time == 0) && !(bridge->b_device[slot].reg & BRIDGE_DEV_RT) && - (device == 0x5 /* RAD_DEV */)) { + device_reg = pcireg_device_get(pcibr_soft, slot); + if ((lt_time == 0) && !(device_reg & BRIDGE_DEV_RT)) { unsigned min_gnt; unsigned min_gnt_mult; @@ -272,12 +255,14 @@ "func=%d, to 0x20\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func)); } + } - /* Get the PCI-X capability if running in PCI-X mode. If the func - * doesnt have a pcix capability, allocate a PCIIO_VENDOR_ID_NONE - * pcibr_info struct so the device driver for that function is not - * called. - */ + /* Get the PCI-X capability if running in PCI-X mode. If the func + * doesnt have a pcix capability, allocate a PCIIO_VENDOR_ID_NONE + * pcibr_info struct so the device driver for that function is not + * called. + */ + if (IS_PCIX(pcibr_soft)) { if (!(pcix_cap = pcibr_find_capability(cfgw, PCI_CAP_PCIX))) { printk(KERN_WARNING "%s: Bus running in PCI-X mode, But card in slot %d, " @@ -398,7 +383,31 @@ } if (base != 0) { /* estimate size */ + pciio_space_t tmp_space = space; + iopaddr_t tmp_base; + size = base & -base; + + /* + * Reserve this space in the relavent address map. Don't + * care about the return code from pcibr_bus_addr_alloc(). + */ + + if (space == PCIIO_SPACE_MEM && code != PCI_BA_MEM_1MEG) { + tmp_space = PCIIO_SPACE_MEM32; + } + + tmp_base = pcibr_bus_addr_alloc(pcibr_soft, + &pcibr_info->f_window[win], + tmp_space, + base, size, 0); + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, + "pcibr_slot_info_init: slot=%d, func=%d win %d " + "reserving space %s [0x%lx..0x%lx], tmp_base 0x%lx\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, win, + pci_space[tmp_space], (uint64_t)base, + (uint64_t)(base + size - 1), (uint64_t)tmp_base)); } else { /* calculate size */ do_pcibr_config_set(wptr, (win * 4), 4, ~0); /* write 1's */ size = do_pcibr_config_get(wptr, (win * 4), 4); /* read back */ @@ -419,7 +428,7 @@ } /* next win */ } /* next func */ - return(0); + return 0; } /* @@ -438,7 +447,7 @@ /* Check to see if there is a capabilities pointer in the cfg header */ if (!(do_pcibr_config_get(cfgw, PCI_CFG_STATUS, 2) & PCI_STAT_CAP_LIST)) { - return (NULL); + return NULL; } /* @@ -453,13 +462,13 @@ while (cap_nxt && (defend_against_circular_linkedlist <= 48)) { cap_id = do_pcibr_config_get(cfgw, cap_nxt, 1); if (cap_id == capability) { - return ((cfg_p)((char *)cfgw + cap_nxt)); + return (cfg_p)((char *)cfgw + cap_nxt); } cap_nxt = (do_pcibr_config_get(cfgw, cap_nxt+1, 1) & 0xfc); defend_against_circular_linkedlist++; } - return (NULL); + return NULL; } /* @@ -478,10 +487,10 @@ pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) - return(EINVAL); + return -EINVAL; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(EINVAL); + return -EINVAL; nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; @@ -491,7 +500,7 @@ kfree(pcibr_infoh); pcibr_soft->bs_slot[slot].bss_ninfo = 0; - return(0); + return 0; } /* @@ -508,13 +517,13 @@ int func; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(EINVAL); + return -EINVAL; if ((nfunc = pcibr_soft->bs_slot[slot].bss_ninfo) < 1) - return(EINVAL); + return -EINVAL; if (!(pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos)) - return(EINVAL); + return -EINVAL; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl, "pcibr_slot_pcix_rbar_init for slot %d\n", @@ -586,7 +595,7 @@ pcibr_soft->bs_pcix_rbar_inuse, pcibr_soft->bs_pcix_rbar_avail)); } - return(0); + return 0; } int as_debug = 0; @@ -602,41 +611,38 @@ pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; - bridge_t *bridge; iopaddr_t mask; int nbars; int nfunc; int func; int win; int rc = 0; - int align; + int align = 0; int align_slot; pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) - return(EINVAL); + return -EINVAL; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(EINVAL); - - bridge = pcibr_soft->bs_base; + return -EINVAL; /* allocate address space, * for windows that have not been * previously assigned. */ if (pcibr_soft->bs_slot[slot].has_host) { - return(0); + return 0; } nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; if (nfunc < 1) - return(EINVAL); + return -EINVAL; pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; if (!pcibr_infoh) - return(EINVAL); + return -EINVAL; /* * Try to make the DevIO windows not @@ -668,7 +674,7 @@ if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) continue; - cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); + cfgw = pcibr_func_config_addr(pcibr_soft, 0, slot, func, 0); wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; if ((do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0) @@ -821,7 +827,7 @@ do_pcibr_config_set(cfgw, PCI_CFG_COMMAND, 4, pci_cfg_cmd_reg | pci_cfg_cmd_reg_add); } /* next func */ - return(rc); + return rc; } /* @@ -834,40 +840,45 @@ pciio_slot_t slot) { pcibr_soft_t pcibr_soft; - bridge_t *bridge; - bridgereg_t devreg; + uint64_t devreg; pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) - return(EINVAL); + return -EINVAL; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(EINVAL); - - bridge = pcibr_soft->bs_base; + return -EINVAL; /* - * Adjustments to Device(x) - * and init of bss_device shadow + * Adjustments to Device(x) and init of bss_device shadow */ - devreg = bridge->b_device[slot].reg; + devreg = pcireg_device_get(pcibr_soft, slot); devreg &= ~BRIDGE_DEV_PAGE_CHK_DIS; /* - * PIC WAR. PV# 855271 - * Don't enable virtual channels in the PIC by default. - * Can cause problems with 32-bit devices. (The bit is only intended - * for 64-bit devices). We set the bit in pcibr_try_set_device() - * if we're 64-bit and requesting virtual channels. + * Enable virtual channels by default (exception: see PIC WAR below) */ - if (PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) - devreg |= BRIDGE_DEV_COH; - else - devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN; + devreg |= BRIDGE_DEV_VIRTUAL_EN; + + /* + * PIC WAR. PV# 855271: Disable virtual channels in the PIC since + * it can cause problems with 32-bit devices. We'll set the bit in + * pcibr_try_set_device() iff we're 64-bit and requesting virtual + * channels. + */ + if (PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) { + devreg &= ~BRIDGE_DEV_VIRTUAL_EN; + } + devreg |= BRIDGE_DEV_COH; + pcibr_soft->bs_slot[slot].bss_device = devreg; - bridge->b_device[slot].reg = devreg; - return(0); + pcireg_device_set(pcibr_soft, slot, devreg); + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pcibr_vhdl, + "pcibr_slot_device_init: Device(%d): 0x%x\n", + slot, devreg)); + return 0; } /* @@ -886,10 +897,10 @@ pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) - return(EINVAL); + return -EINVAL; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(EINVAL); + return -EINVAL; slotp = &pcibr_soft->bs_slot[slot]; @@ -901,7 +912,7 @@ if (pcibr_soft->bs_slot[slot].bss_ninfo < 1) { pcibr_infoh = kmalloc(sizeof (*(pcibr_infoh)), GFP_KERNEL); if ( !pcibr_infoh ) { - return ENOMEM; + return -ENOMEM; } memset(pcibr_infoh, 0, sizeof (*(pcibr_infoh))); @@ -939,7 +950,7 @@ EDGE_LBL_GUEST); } - return(0); + return 0; } @@ -966,13 +977,13 @@ pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) - return(EINVAL); + return -EINVAL; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(EINVAL); + return -EINVAL; if (pcibr_soft->bs_slot[slot].has_host) { - return(EPERM); + return -EPERM; } xconn_vhdl = pcibr_soft->bs_conn; @@ -1018,7 +1029,7 @@ pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; } - return(error); + return error; } /* @@ -1044,13 +1055,13 @@ pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) - return(EINVAL); + return -EINVAL; if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(EINVAL); + return -EINVAL; if (pcibr_soft->bs_slot[slot].has_host) - return(EPERM); + return -EPERM; nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; @@ -1105,45 +1116,7 @@ pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; } - return(error); -} - -/* - * pcibr_slot_attach - * This is a place holder routine to keep track of all the - * slot-specific initialization that needs to be done. - * This is usually called when we want to initialize a new - * PCI card on the bus. - */ -int -pcibr_slot_attach(vertex_hdl_t pcibr_vhdl, - pciio_slot_t slot, - int drv_flags, - char *l1_msg, - int *sub_errorp) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - int error; - - /* Do not allow a multi-function card to be hot-plug inserted */ - if (pcibr_soft->bs_slot[slot].bss_ninfo > 1) { - if (sub_errorp) - *sub_errorp = EPERM; - return(PCI_MULTI_FUNC_ERR); - } - - /* Call the device attach */ - error = pcibr_slot_call_device_attach(pcibr_vhdl, slot, drv_flags); - if (error) { - if (sub_errorp) - *sub_errorp = error; - if (error == EUNATCH) - return(PCI_NO_DRIVER); - else - return(PCI_SLOT_DRV_ATTACH_ERR); - } - - return(0); + return error; } /* @@ -1166,7 +1139,9 @@ if (error) { if (sub_errorp) *sub_errorp = error; - return(PCI_SLOT_DRV_DETACH_ERR); + if (l1_msg) + ; + return PCI_SLOT_DRV_DETACH_ERR; } /* Recalculate the RBARs for all the devices on the bus since we've @@ -1185,7 +1160,7 @@ (void)pcibr_slot_pcix_rbar_init(pcibr_soft, tmp_slot); } - return (0); + return 0; } @@ -1197,33 +1172,35 @@ * through the valp parameter. */ static int -pcibr_probe_slot_pic(bridge_t *bridge, - cfg_p cfg, - unsigned *valp) +pcibr_probe_slot(pcibr_soft_t pcibr_soft, + cfg_p cfg, + unsigned *valp) { - int rv; - picreg_t p_old_enable = (picreg_t)0, p_new_enable; - extern int snia_badaddr_val(volatile void *, int, volatile void *); - - p_old_enable = bridge->p_int_enable_64; - p_new_enable = p_old_enable & ~(BRIDGE_IMR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT); - bridge->p_int_enable_64 = p_new_enable; - - if (bridge->p_err_int_view_64 & (BRIDGE_ISR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT)) - bridge->p_int_rst_stat_64 = BRIDGE_IRR_MULTI_CLR; - - if (bridge->p_int_status_64 & (BRIDGE_IRR_PCI_GRP | PIC_PCIX_GRP_CLR)) { - bridge->p_int_rst_stat_64 = (BRIDGE_IRR_PCI_GRP_CLR | PIC_PCIX_GRP_CLR); - (void) bridge->b_wid_tflush; /* flushbus */ - } - rv = snia_badaddr_val((void *) cfg, 4, valp); - if (bridge->p_err_int_view_64 & (BRIDGE_ISR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT)) { - bridge->p_int_rst_stat_64 = BRIDGE_IRR_MULTI_CLR; - rv = 1; /* unoccupied slot */ + return pcibr_probe_work(pcibr_soft, (void *)cfg, 4, (void *)valp); +} + +/* + * Probe an offset within a piomap with errors disabled. + * len must be 1, 2, 4, or 8. The probed address must be a multiple of + * len. + * + * Returns: 0 if the offset was probed and put valid data in valp + * -1 if there was a usage error such as improper alignment + * or out of bounds offset/len combination. In this + * case, the map was not probed + * 1 if the offset was probed but resulted in an error + * such as device not responding, bus error, etc. + */ + +int +pcibr_piomap_probe(pcibr_piomap_t piomap, off_t offset, int len, void *valp) +{ + if (offset + len > piomap->bp_mapsz) { + return -1; } - bridge->p_int_enable_64 = p_old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - return(rv); + + return pcibr_probe_work(piomap->bp_soft, + piomap->bp_kvaddr + offset, len, valp); } /* @@ -1234,11 +1211,31 @@ * through the valp parameter. */ static int -pcibr_probe_slot(bridge_t *bridge, - cfg_p cfg, - unsigned *valp) +pcibr_probe_work(pcibr_soft_t pcibr_soft, + void *addr, + int len, + void *valp) { - return(pcibr_probe_slot_pic(bridge, cfg, valp)); + int rv; + + /* + * Sanity checks ... + */ + + if (len != 1 && len != 2 && len != 4 && len != 8) { + return -1; /* invalid len */ + } + + if ((uint64_t)addr & (len-1)) { + return -1; /* invalid alignment */ + } + + rv = snia_badaddr_val((void *)addr, len, valp); + + /* Clear the int_view register incase it was set */ + pcireg_intr_reset_set(pcibr_soft, BRIDGE_IRR_MULTI_CLR); + + return (rv ? 1 : 0); /* return 1 for snia_badaddr_val error, 0 if ok */ } @@ -1249,7 +1246,6 @@ pcibr_info_t pcibr_info; pciio_function_t func; pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[slot]; - bridge_t *bridge = pcibr_soft->bs_base; cfg_p cfgw; int nfunc = slotp->bss_ninfo; int bar; @@ -1267,7 +1263,7 @@ s = pcibr_lock(pcibr_soft); /* Disable memory and I/O BARs */ - cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); + cfgw = pcibr_func_config_addr(pcibr_soft, 0, slot, func, 0); cmd_reg = do_pcibr_config_get(cfgw, PCI_CFG_COMMAND, 4); cmd_reg &= (PCI_CMD_MEM_SPACE | PCI_CMD_IO_SPACE); do_pcibr_config_set(cfgw, PCI_CFG_COMMAND, 4, cmd_reg); @@ -1277,7 +1273,7 @@ continue; /* Free the PCI bus space */ - pciibr_bus_addr_free(pcibr_soft, &pcibr_info->f_window[bar]); + pcibr_bus_addr_free(&pcibr_info->f_window[bar]); /* Get index of the DevIO(x) register used to access this BAR */ devio_index = pcibr_info->f_window[bar].w_devio_index; @@ -1295,7 +1291,7 @@ /* Free the Expansion ROM PCI bus space */ if(pcibr_info->f_rbase && pcibr_info->f_rsize) { - pciibr_bus_addr_free(pcibr_soft, &pcibr_info->f_rwindow); + pcibr_bus_addr_free(&pcibr_info->f_rwindow); } pcibr_unlock(pcibr_soft, s); @@ -1317,12 +1313,6 @@ slotp->bss_d64_flags = 0; slotp->bss_d32_base = PCIBR_D32_BASE_UNSET; slotp->bss_d32_flags = 0; - - /* Clear out shadow info necessary for the external SSRAM workaround */ - slotp->bss_ext_ates_active = ATOMIC_INIT(0); - slotp->bss_cmd_pointer = 0; - slotp->bss_cmd_shadow = 0; - } @@ -1360,12 +1350,12 @@ ? &win_info_p->w_win_alloc : NULL, start, size, align); - return(iopaddr); + return iopaddr; } void -pciibr_bus_addr_free(pcibr_soft_t pcibr_soft, pciio_win_info_t win_info_p) +pcibr_bus_addr_free(pciio_win_info_t win_info_p) { pciio_device_win_free(&win_info_p->w_win_alloc); } @@ -1381,17 +1371,16 @@ pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); xwidgetnum_t widget = pcibr_soft->bs_xid; int bricktype = pcibr_soft->bs_bricktype; - int bus = pcibr_soft->bs_busnum; + int bus; - /* - * For PIC there are 2 busses per widget and pcibr_soft->bs_busnum - * will be 0 or 1. For [X]BRIDGE there is 1 bus per widget and - * pcibr_soft->bs_busnum will always be zero. So we add bs_busnum - * to what io_brick_map_widget returns to get the bus number. - */ - if ((bus += io_brick_map_widget(bricktype, widget)) > 0) { - return bus; - } else { + if ((bus = io_brick_map_widget(bricktype, widget)) <= 0) { + printk(KERN_WARNING "pcibr_widget_to_bus() bad bricktype %d\n", bricktype); return 0; } + + /* For PIC there are 2 busses per widget and pcibr_soft->bs_busnum + * will be 0 or 1. Add in the correct PIC bus offset. + */ + bus += pcibr_soft->bs_busnum; + return bus; } --- diff/arch/ia64/sn/io/sn2/pciio.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/pciio.c 2004-02-09 10:39:51.000000000 +0000 @@ -304,13 +304,6 @@ (dev, addr, size); } -void -pciio_dmalist_drain(vertex_hdl_t dev, alenlist_t list) -{ - DEV_FUNC(dev, dmalist_drain) - (dev, list); -} - /* ===================================================================== * INTERRUPT MANAGEMENT * @@ -703,30 +696,6 @@ return (pciio_info->c_pops); } -int -pciio_businfo_multi_master_get(pciio_businfo_t businfo) -{ - return businfo->bi_multi_master; -} - -pciio_asic_type_t -pciio_businfo_asic_type_get(pciio_businfo_t businfo) -{ - return businfo->bi_asic_type; -} - -pciio_bus_type_t -pciio_businfo_bus_type_get(pciio_businfo_t businfo) -{ - return businfo->bi_bus_type; -} - -pciio_bus_speed_t -pciio_businfo_bus_speed_get(pciio_businfo_t businfo) -{ - return businfo->bi_bus_speed; -} - /* ===================================================================== * GENERIC PCI INITIALIZATION FUNCTIONS */ @@ -792,9 +761,12 @@ pciio_info = kmalloc(sizeof (*(pciio_info)), GFP_KERNEL); if ( pciio_info ) memset(pciio_info, 0, sizeof (*(pciio_info))); + else { + printk(KERN_WARNING "pciio_device_info_new(): Unable to " + "allocate memory\n"); + return NULL; + } } - ASSERT(pciio_info != NULL); - pciio_info->c_slot = slot; pciio_info->c_func = func; pciio_info->c_vendor = vendor_id; @@ -859,13 +831,8 @@ pciio_info->c_slot, pciio_info->c_func); - hwgraph_edge_remove(connectpt,name,&pconn); pciio_info_set(pconn,0); - /* Remove the link to our pci provider */ - hwgraph_edge_remove(pconn, EDGE_LBL_MASTER, NULL); - - hwgraph_vertex_unref(pconn); hwgraph_vertex_destroy(pconn); @@ -1036,12 +1003,3 @@ { return (pci_info->c_type1); } - -pciio_businfo_t -pciio_businfo_get(vertex_hdl_t conn) -{ - pciio_info_t info; - - info = pciio_info_get(conn); - return DEV_FUNC(conn, businfo_get)(conn); -} --- diff/arch/ia64/sn/io/sn2/pic.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/pic.c 2004-02-09 10:39:51.000000000 +0000 @@ -17,12 +17,41 @@ #include #include +extern struct file_operations pcibr_fops; +extern pcibr_list_p pcibr_list; -#define PCI_BUS_NO_1 1 +static int pic_attach2(vertex_hdl_t, void *, vertex_hdl_t, + int, pcibr_soft_t *); + +extern int isIO9(nasid_t); +extern char *dev_to_name(vertex_hdl_t dev, char *buf, uint buflen); +extern int pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl); +extern pcibr_hints_t pcibr_hints_get(vertex_hdl_t, int); +extern unsigned pcibr_intr_bits(pciio_info_t info, + pciio_intr_line_t lines, int nslots); +extern void pcibr_setwidint(xtalk_intr_t); +extern int pcibr_error_handler_wrapper(error_handler_arg_t, int, + ioerror_mode_t, ioerror_t *); +extern void pcibr_error_intr_handler(intr_arg_t); +extern void pcibr_directmap_init(pcibr_soft_t); +extern int pcibr_slot_info_init(vertex_hdl_t,pciio_slot_t); +extern int pcibr_slot_addr_space_init(vertex_hdl_t,pciio_slot_t); +extern int pcibr_slot_device_init(vertex_hdl_t, pciio_slot_t); +extern int pcibr_slot_pcix_rbar_init(pcibr_soft_t, pciio_slot_t); +extern int pcibr_slot_guest_info_init(vertex_hdl_t,pciio_slot_t); +extern int pcibr_slot_call_device_attach(vertex_hdl_t, + pciio_slot_t, int); +extern void pcibr_rrb_alloc_init(pcibr_soft_t, int, int, int); +extern int pcibr_pcix_rbars_calc(pcibr_soft_t); +extern pcibr_info_t pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, + pciio_function_t, pciio_vendor_id_t, + pciio_device_id_t); +extern int pcibr_initial_rrb(vertex_hdl_t, pciio_slot_t, + pciio_slot_t); +extern void xwidget_error_register(vertex_hdl_t, error_handler_f *, + error_handler_arg_t); +extern void pcibr_clearwidint(pcibr_soft_t); -extern int pcibr_attach2(vertex_hdl_t, bridge_t *, vertex_hdl_t, int, pcibr_soft_t *); -extern void pcibr_driver_reg_callback(vertex_hdl_t, int, int, int); -extern void pcibr_driver_unreg_callback(vertex_hdl_t, int, int, int); /* @@ -30,10 +59,9 @@ */ static int pic_bus1_widget_info_dup(vertex_hdl_t conn_v, vertex_hdl_t peer_conn_v, - cnodeid_t xbow_peer) + cnodeid_t xbow_peer, char *peer_path) { xwidget_info_t widget_info, peer_widget_info; - char peer_path[256]; vertex_hdl_t peer_hubv; hubinfo_t peer_hub_info; @@ -48,7 +76,7 @@ (arbitrary_info_t *)&widget_info) == GRAPH_SUCCESS) { peer_widget_info = kmalloc(sizeof (*(peer_widget_info)), GFP_KERNEL); if ( !peer_widget_info ) { - return 0; + return -ENOMEM; } memset(peer_widget_info, 0, sizeof (*(peer_widget_info))); @@ -96,7 +124,7 @@ char pathname[256], peer_path[256], tmpbuf[256]; char *p; int rc; - vertex_hdl_t peer_conn_v; + vertex_hdl_t peer_conn_v, hubv; int pos; slabid_t slab; @@ -141,9 +169,15 @@ * vertex but that should be safe and we don't * really expect the additions to fail anyway. */ - if (!pic_bus1_widget_info_dup(conn_v, peer_conn_v, xbow_peer)) + if (!pic_bus1_widget_info_dup(conn_v, peer_conn_v, + xbow_peer, peer_path)) return 0; + hubv = cnodeid_to_vertex(xbow_peer); + ASSERT(hubv != GRAPH_VERTEX_NONE); + device_master_set(peer_conn_v, hubv); + xtalk_provider_register(hubv, &hub_provider); + xtalk_provider_startup(hubv); return peer_conn_v; } } @@ -151,12 +185,15 @@ return 0; } - +/* + * PIC has two buses under a single widget. pic_attach() calls pic_attach2() + * to attach each of those buses. + */ int pic_attach(vertex_hdl_t conn_v) { int rc; - bridge_t *bridge0, *bridge1 = (bridge_t *)0; + void *bridge0, *bridge1 = (void *)0; vertex_hdl_t pcibr_vhdl0, pcibr_vhdl1 = (vertex_hdl_t)0; pcibr_soft_t bus0_soft, bus1_soft = (pcibr_soft_t)0; vertex_hdl_t conn_v0, conn_v1, peer_conn_v; @@ -165,9 +202,8 @@ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, "pic_attach()\n")); - bridge0 = (bridge_t *) xtalk_piotrans_addr(conn_v, NULL, - 0, sizeof(bridge_t), 0); - bridge1 = (bridge_t *)((char *)bridge0 + PIC_BUS1_OFFSET); + bridge0 = pcibr_bridge_ptr_get(conn_v, 0); + bridge1 = pcibr_bridge_ptr_get(conn_v, 1); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, "pic_attach: bridge0=0x%lx, bridge1=0x%lx\n", @@ -215,8 +251,23 @@ pciio_provider_startup(pcibr_vhdl0); pciio_provider_startup(pcibr_vhdl1); - pcibr_attach2(conn_v0, bridge0, pcibr_vhdl0, 0, &bus0_soft); - pcibr_attach2(conn_v1, bridge1, pcibr_vhdl1, 1, &bus1_soft); + pic_attach2(conn_v0, bridge0, pcibr_vhdl0, 0, &bus0_soft); + pic_attach2(conn_v1, bridge1, pcibr_vhdl1, 1, &bus1_soft); + + { + /* If we're dual-ported finish duplicating the peer info structure. + * The error handler and arg are done in pic_attach2(). + */ + xwidget_info_t info0, info1; + if (conn_v0 != conn_v1) { /* dual ported */ + info0 = xwidget_info_get(conn_v0); + info1 = xwidget_info_get(conn_v1); + if (info1->w_efunc == (error_handler_f *)NULL) + info1->w_efunc = info0->w_efunc; + if (info1->w_einfo == (error_handler_arg_t)0) + info1->w_einfo = bus1_soft; + } + } /* save a pointer to the PIC's other bus's soft struct */ bus0_soft->bs_peers_soft = bus1_soft; @@ -229,6 +280,506 @@ return 0; } + +/* + * PIC has two buses under a single widget. pic_attach() calls pic_attach2() + * to attach each of those buses. + */ +static int +pic_attach2(vertex_hdl_t xconn_vhdl, void *bridge, + vertex_hdl_t pcibr_vhdl, int busnum, pcibr_soft_t *ret_softp) +{ + vertex_hdl_t ctlr_vhdl; + pcibr_soft_t pcibr_soft; + pcibr_info_t pcibr_info; + xwidget_info_t info; + xtalk_intr_t xtalk_intr; + pcibr_list_p self; + int entry, slot, ibit, i; + vertex_hdl_t noslot_conn; + char devnm[MAXDEVNAME], *s; + pcibr_hints_t pcibr_hints; + picreg_t id; + picreg_t int_enable; + picreg_t pic_ctrl_reg; + + int iobrick_type_get_nasid(nasid_t nasid); + int iomoduleid_get(nasid_t nasid); + int irq; + int cpu; + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, + "pic_attach2: bridge=0x%lx, busnum=%d\n", bridge, busnum)); + + ctlr_vhdl = NULL; + ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, 0, + 0, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + (struct file_operations *)&pcibr_fops, (void *)pcibr_vhdl); + ASSERT(ctlr_vhdl != NULL); + + id = pcireg_bridge_id_get(bridge); + hwgraph_info_add_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, + (arbitrary_info_t)XWIDGET_PART_REV_NUM(id)); + + /* + * Get the hint structure; if some NIC callback marked this vertex as + * "hands-off" then we just return here, before doing anything else. + */ + pcibr_hints = pcibr_hints_get(xconn_vhdl, 0); + + if (pcibr_hints && pcibr_hints->ph_hands_off) + return -1; + + /* allocate soft structure to hang off the vertex. Link the new soft + * structure to the pcibr_list linked list + */ + pcibr_soft = kmalloc(sizeof (*(pcibr_soft)), GFP_KERNEL); + if ( !pcibr_soft ) + return -ENOMEM; + + self = kmalloc(sizeof (*(self)), GFP_KERNEL); + if ( !self ) { + kfree(pcibr_soft); + return -ENOMEM; + } + memset(pcibr_soft, 0, sizeof (*(pcibr_soft))); + memset(self, 0, sizeof (*(self))); + + self->bl_soft = pcibr_soft; + self->bl_vhdl = pcibr_vhdl; + self->bl_next = pcibr_list; + pcibr_list = self; + + if (ret_softp) + *ret_softp = pcibr_soft; + + memset(pcibr_soft, 0, sizeof *pcibr_soft); + pcibr_soft_set(pcibr_vhdl, pcibr_soft); + + s = dev_to_name(pcibr_vhdl, devnm, MAXDEVNAME); + pcibr_soft->bs_name = kmalloc(strlen(s) + 1, GFP_KERNEL); + strcpy(pcibr_soft->bs_name, s); + + pcibr_soft->bs_conn = xconn_vhdl; + pcibr_soft->bs_vhdl = pcibr_vhdl; + pcibr_soft->bs_base = (void *)bridge; + pcibr_soft->bs_rev_num = XWIDGET_PART_REV_NUM(id); + pcibr_soft->bs_intr_bits = (pcibr_intr_bits_f *)pcibr_intr_bits; + pcibr_soft->bsi_err_intr = 0; + pcibr_soft->bs_min_slot = 0; + pcibr_soft->bs_max_slot = 3; + pcibr_soft->bs_busnum = busnum; + pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_PIC; + pcibr_soft->bs_int_ate_size = PIC_INTERNAL_ATES; + /* Make sure this is called after setting the bs_base and bs_bridge_type */ + pcibr_soft->bs_bridge_mode = (pcireg_speed_get(pcibr_soft) << 1) | + pcireg_mode_get(pcibr_soft); + + info = xwidget_info_get(xconn_vhdl); + pcibr_soft->bs_xid = xwidget_info_id_get(info); + pcibr_soft->bs_master = xwidget_info_master_get(info); + pcibr_soft->bs_mxid = xwidget_info_masterid_get(info); + + strcpy(pcibr_soft->bs_asic_name, "PIC"); + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, + "pic_attach2: pcibr_soft=0x%lx, mode=0x%x\n", + pcibr_soft, pcibr_soft->bs_bridge_mode)); + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, + "pic_attach2: %s ASIC: rev %s (code=0x%x)\n", + pcibr_soft->bs_asic_name, + (IS_PIC_PART_REV_A(pcibr_soft->bs_rev_num)) ? "A" : + (IS_PIC_PART_REV_B(pcibr_soft->bs_rev_num)) ? "B" : + (IS_PIC_PART_REV_C(pcibr_soft->bs_rev_num)) ? "C" : + "unknown", pcibr_soft->bs_rev_num)); + + /* PV854845: Must clear write request buffer to avoid parity errors */ + for (i=0; i < PIC_WR_REQ_BUFSIZE; i++) { + ((pic_t *)bridge)->p_wr_req_lower[i] = 0; + ((pic_t *)bridge)->p_wr_req_upper[i] = 0; + ((pic_t *)bridge)->p_wr_req_parity[i] = 0; + } + + pcibr_soft->bs_nasid = NASID_GET(bridge); + + pcibr_soft->bs_bricktype = iobrick_type_get_nasid(pcibr_soft->bs_nasid); + if (pcibr_soft->bs_bricktype < 0) + printk(KERN_WARNING "%s: bricktype was unknown by L1 (ret val = 0x%x)\n", + pcibr_soft->bs_name, pcibr_soft->bs_bricktype); + + pcibr_soft->bs_moduleid = iomoduleid_get(pcibr_soft->bs_nasid); + + if (pcibr_soft->bs_bricktype > 0) { + switch (pcibr_soft->bs_bricktype) { + case MODULE_PXBRICK: + case MODULE_IXBRICK: + case MODULE_OPUSBRICK: + pcibr_soft->bs_first_slot = 0; + pcibr_soft->bs_last_slot = 1; + pcibr_soft->bs_last_reset = 1; + + /* Bus 1 of IXBrick has a IO9, so there are 4 devices, not 2 */ + if ((pcibr_widget_to_bus(pcibr_vhdl) == 1) + && isIO9(pcibr_soft->bs_nasid)) { + pcibr_soft->bs_last_slot = 3; + pcibr_soft->bs_last_reset = 3; + } + break; + + case MODULE_CGBRICK: + pcibr_soft->bs_first_slot = 0; + pcibr_soft->bs_last_slot = 0; + pcibr_soft->bs_last_reset = 0; + break; + + default: + printk(KERN_WARNING "%s: Unknown bricktype: 0x%x\n", + pcibr_soft->bs_name, pcibr_soft->bs_bricktype); + break; + } + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, + "pic_attach2: bricktype=%d, brickbus=%d, " + "slots %d-%d\n", pcibr_soft->bs_bricktype, + pcibr_widget_to_bus(pcibr_vhdl), + pcibr_soft->bs_first_slot, pcibr_soft->bs_last_slot)); + } + + /* + * Initialize bridge and bus locks + */ + spin_lock_init(&pcibr_soft->bs_lock); + + /* + * If we have one, process the hints structure. + */ + if (pcibr_hints) { + unsigned rrb_fixed; + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, pcibr_vhdl, + "pic_attach2: pcibr_hints=0x%lx\n", pcibr_hints)); + + rrb_fixed = pcibr_hints->ph_rrb_fixed; + + pcibr_soft->bs_rrb_fixed = rrb_fixed; + + if (pcibr_hints->ph_intr_bits) + pcibr_soft->bs_intr_bits = pcibr_hints->ph_intr_bits; + + + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { + int hslot = pcibr_hints->ph_host_slot[slot] - 1; + + if (hslot < 0) { + pcibr_soft->bs_slot[slot].host_slot = slot; + } else { + pcibr_soft->bs_slot[slot].has_host = 1; + pcibr_soft->bs_slot[slot].host_slot = hslot; + } + } + } + + /* + * Set-up initial values for state fields + */ + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { + pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE; + pcibr_soft->bs_slot[slot].bss_devio.bssd_ref_cnt = 0; + pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET; + pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET; + pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0] = -1; + } + + for (ibit = 0; ibit < 8; ++ibit) { + pcibr_soft->bs_intr[ibit].bsi_xtalk_intr = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_soft = pcibr_soft; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_ibit = ibit; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0; + pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0; + } + + + /* + * connect up our error handler. PIC has 2 busses (thus resulting in 2 + * pcibr_soft structs under 1 widget), so only register a xwidget error + * handler for PIC's bus0. NOTE: for PIC pcibr_error_handler_wrapper() + * is a wrapper routine we register that will call the real error handler + * pcibr_error_handler() with the correct pcibr_soft struct. + */ + if (busnum == 0) { + xwidget_error_register(xconn_vhdl, + pcibr_error_handler_wrapper, pcibr_soft); + } + + /* + * Clear all pending interrupts. Assume all interrupts are from slot 3 + * until otherise setup. + */ + pcireg_intr_reset_set(pcibr_soft, PIC_IRR_ALL_CLR); + pcireg_intr_device_set(pcibr_soft, 0x006db6db); + + /* Setup the mapping register used for direct mapping */ + pcibr_directmap_init(pcibr_soft); + + /* + * Initialize the PICs control register. + */ + pic_ctrl_reg = pcireg_control_get(pcibr_soft); + + /* Bridges Requester ID: bus = busnum, dev = 0, func = 0 */ + pic_ctrl_reg &= ~PIC_CTRL_BUS_NUM_MASK; + pic_ctrl_reg |= PIC_CTRL_BUS_NUM(busnum); + pic_ctrl_reg &= ~PIC_CTRL_DEV_NUM_MASK; + pic_ctrl_reg &= ~PIC_CTRL_FUN_NUM_MASK; + + pic_ctrl_reg &= ~PIC_CTRL_NO_SNOOP; + pic_ctrl_reg &= ~PIC_CTRL_RELAX_ORDER; + + /* enable parity checking on PICs internal RAM */ + pic_ctrl_reg |= PIC_CTRL_PAR_EN_RESP; + pic_ctrl_reg |= PIC_CTRL_PAR_EN_ATE; + + /* PIC BRINGUP WAR (PV# 862253): dont enable write request parity */ + if (!PCIBR_WAR_ENABLED(PV862253, pcibr_soft)) { + pic_ctrl_reg |= PIC_CTRL_PAR_EN_REQ; + } + + pic_ctrl_reg |= PIC_CTRL_PAGE_SIZE; + + pcireg_control_set(pcibr_soft, pic_ctrl_reg); + + /* Initialize internal mapping entries (ie. the ATEs) */ + for (entry = 0; entry < pcibr_soft->bs_int_ate_size; entry++) + pcireg_int_ate_set(pcibr_soft, entry, 0); + + pcibr_soft->bs_int_ate_resource.start = 0; + pcibr_soft->bs_int_ate_resource.end = pcibr_soft->bs_int_ate_size - 1; + + /* Setup the PICs error interrupt handler. */ + xtalk_intr = xtalk_intr_alloc(xconn_vhdl, (device_desc_t)0, pcibr_vhdl); + + ASSERT(xtalk_intr != NULL); + + irq = ((hub_intr_t)xtalk_intr)->i_bit; + cpu = ((hub_intr_t)xtalk_intr)->i_cpuid; + + intr_unreserve_level(cpu, irq); + ((hub_intr_t)xtalk_intr)->i_bit = SGI_PCIBR_ERROR; + xtalk_intr->xi_vector = SGI_PCIBR_ERROR; + + pcibr_soft->bsi_err_intr = xtalk_intr; + + /* + * On IP35 with XBridge, we do some extra checks in pcibr_setwidint + * in order to work around some addressing limitations. In order + * for that fire wall to work properly, we need to make sure we + * start from a known clean state. + */ + pcibr_clearwidint(pcibr_soft); + + xtalk_intr_connect(xtalk_intr, + (intr_func_t) pcibr_error_intr_handler, + (intr_arg_t) pcibr_soft, + (xtalk_intr_setfunc_t) pcibr_setwidint, + (void *) pcibr_soft); + + request_irq(SGI_PCIBR_ERROR, (void *)pcibr_error_intr_handler, SA_SHIRQ, + "PCIBR error", (intr_arg_t) pcibr_soft); + + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_vhdl, + "pcibr_setwidint: target_id=0x%lx, int_addr=0x%lx\n", + pcireg_intr_dst_target_id_get(pcibr_soft), + pcireg_intr_dst_addr_get(pcibr_soft))); + + /* now we can start handling error interrupts */ + int_enable = pcireg_intr_enable_get(pcibr_soft); + int_enable |= PIC_ISR_ERRORS; + + /* PIC BRINGUP WAR (PV# 856864 & 856865): allow the tnums that are + * locked out to be freed up sooner (by timing out) so that the + * read tnums are never completely used up. + */ + if (PCIBR_WAR_ENABLED(PV856864, pcibr_soft)) { + int_enable &= ~PIC_ISR_PCIX_REQ_TOUT; + int_enable &= ~PIC_ISR_XREAD_REQ_TIMEOUT; + + pcireg_req_timeout_set(pcibr_soft, 0x750); + } + + pcireg_intr_enable_set(pcibr_soft, int_enable); + pcireg_intr_mode_set(pcibr_soft, 0); /* dont send 'clear interrupt' pkts */ + pcireg_tflush_get(pcibr_soft); /* wait until Bridge PIO complete */ + + /* + * PIC BRINGUP WAR (PV# 856866, 859504, 861476, 861478): Don't use + * RRB0, RRB8, RRB1, and RRB9. Assign them to DEVICE[2|3]--VCHAN3 + * so they are not used. This works since there is currently no + * API to penable VCHAN3. + */ + if (PCIBR_WAR_ENABLED(PV856866, pcibr_soft)) { + pcireg_rrb_bit_set(pcibr_soft, 0, 0x000f000f); /* even rrb reg */ + pcireg_rrb_bit_set(pcibr_soft, 1, 0x000f000f); /* odd rrb reg */ + } + + /* PIC only supports 64-bit direct mapping in PCI-X mode. Since + * all PCI-X devices that initiate memory transactions must be + * capable of generating 64-bit addressed, we force 64-bit DMAs. + */ + pcibr_soft->bs_dma_flags = 0; + if (IS_PCIX(pcibr_soft)) { + pcibr_soft->bs_dma_flags |= PCIIO_DMA_A64; + } + + { + + iopaddr_t prom_base_addr = pcibr_soft->bs_xid << 24; + int prom_base_size = 0x1000000; + int status; + struct resource *res; + + /* Allocate resource maps based on bus page size; for I/O and memory + * space, free all pages except those in the base area and in the + * range set by the PROM. + * + * PROM creates BAR addresses in this format: 0x0ws00000 where w is + * the widget number and s is the device register offset for the slot. + */ + + /* Setup the Bus's PCI IO Root Resource. */ + pcibr_soft->bs_io_win_root_resource.start = PCIBR_BUS_IO_BASE; + pcibr_soft->bs_io_win_root_resource.end = 0xffffffff; + res = (struct resource *) kmalloc( sizeof(struct resource), GFP_KERNEL); + if (!res) + panic("PCIBR:Unable to allocate resource structure\n"); + + /* Block off the range used by PROM. */ + res->start = prom_base_addr; + res->end = prom_base_addr + (prom_base_size - 1); + status = request_resource(&pcibr_soft->bs_io_win_root_resource, res); + if (status) + panic("PCIBR:Unable to request_resource()\n"); + + /* Setup the Small Window Root Resource */ + pcibr_soft->bs_swin_root_resource.start = PAGE_SIZE; + pcibr_soft->bs_swin_root_resource.end = 0x000FFFFF; + + /* Setup the Bus's PCI Memory Root Resource */ + pcibr_soft->bs_mem_win_root_resource.start = 0x200000; + pcibr_soft->bs_mem_win_root_resource.end = 0xffffffff; + res = (struct resource *) kmalloc( sizeof(struct resource), GFP_KERNEL); + if (!res) + panic("PCIBR:Unable to allocate resource structure\n"); + + /* Block off the range used by PROM. */ + res->start = prom_base_addr; + res->end = prom_base_addr + (prom_base_size - 1);; + status = request_resource(&pcibr_soft->bs_mem_win_root_resource, res); + if (status) + panic("PCIBR:Unable to request_resource()\n"); + + } + + + /* build "no-slot" connection point */ + pcibr_info = pcibr_device_info_new(pcibr_soft, PCIIO_SLOT_NONE, + PCIIO_FUNC_NONE, PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); + noslot_conn = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c); + + /* Store no slot connection point info for tearing it down during detach. */ + pcibr_soft->bs_noslot_conn = noslot_conn; + pcibr_soft->bs_noslot_info = pcibr_info; + + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { + /* Find out what is out there */ + (void)pcibr_slot_info_init(pcibr_vhdl, slot); + } + + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { + /* Set up the address space for this slot in the PCI land */ + (void)pcibr_slot_addr_space_init(pcibr_vhdl, slot); + } + + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { + /* Setup the device register */ + (void)pcibr_slot_device_init(pcibr_vhdl, slot); + } + + if (IS_PCIX(pcibr_soft)) { + pcibr_soft->bs_pcix_rbar_inuse = 0; + pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR; + pcibr_soft->bs_pcix_rbar_percent_allowed = + pcibr_pcix_rbars_calc(pcibr_soft); + + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { + /* Setup the PCI-X Read Buffer Attribute Registers (RBARs) */ + (void)pcibr_slot_pcix_rbar_init(pcibr_soft, slot); + } + } + + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { + /* Setup host/guest relations */ + (void)pcibr_slot_guest_info_init(pcibr_vhdl, slot); + } + + /* Handle initial RRB management */ + pcibr_initial_rrb(pcibr_vhdl, + pcibr_soft->bs_first_slot, pcibr_soft->bs_last_slot); + + /* Before any drivers get called that may want to re-allocate RRB's, + * let's get some special cases pre-allocated. Drivers may override + * these pre-allocations, but by doing pre-allocations now we're + * assured not to step all over what the driver intended. + */ + if (pcibr_soft->bs_bricktype > 0) { + switch (pcibr_soft->bs_bricktype) { + case MODULE_PXBRICK: + case MODULE_IXBRICK: + case MODULE_OPUSBRICK: + /* + * If IO9 in bus 1, allocate RRBs to all the IO9 devices + */ + if ((pcibr_widget_to_bus(pcibr_vhdl) == 1) && + (pcibr_soft->bs_slot[0].bss_vendor_id == 0x10A9) && + (pcibr_soft->bs_slot[0].bss_device_id == 0x100A)) { + pcibr_rrb_alloc_init(pcibr_soft, 0, VCHAN0, 4); + pcibr_rrb_alloc_init(pcibr_soft, 1, VCHAN0, 4); + pcibr_rrb_alloc_init(pcibr_soft, 2, VCHAN0, 4); + pcibr_rrb_alloc_init(pcibr_soft, 3, VCHAN0, 4); + } else { + pcibr_rrb_alloc_init(pcibr_soft, 0, VCHAN0, 4); + pcibr_rrb_alloc_init(pcibr_soft, 1, VCHAN0, 4); + } + break; + + case MODULE_CGBRICK: + pcibr_rrb_alloc_init(pcibr_soft, 0, VCHAN0, 8); + break; + } /* switch */ + } + + + for (slot = pcibr_soft->bs_min_slot; + slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { + /* Call the device attach */ + (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); + } + + pciio_device_attach(noslot_conn, 0); + + return 0; +} + + /* * pci provider functions * @@ -237,6 +788,8 @@ */ pciio_provider_t pci_pic_provider = { + PCIIO_ASIC_TYPE_PIC, + (pciio_piomap_alloc_f *) pcibr_piomap_alloc, (pciio_piomap_free_f *) pcibr_piomap_free, (pciio_piomap_addr_f *) pcibr_piomap_addr, @@ -252,7 +805,6 @@ (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr, (pciio_dmamap_drain_f *) pcibr_dmamap_drain, (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain, - (pciio_dmalist_drain_f *) pcibr_dmalist_drain, (pciio_intr_alloc_f *) pcibr_intr_alloc, (pciio_intr_free_f *) pcibr_intr_free, @@ -263,12 +815,12 @@ (pciio_provider_startup_f *) pcibr_provider_startup, (pciio_provider_shutdown_f *) pcibr_provider_shutdown, (pciio_reset_f *) pcibr_reset, - (pciio_write_gather_flush_f *) pcibr_write_gather_flush, (pciio_endian_set_f *) pcibr_endian_set, - (pciio_priority_set_f *) pcibr_priority_set, (pciio_config_get_f *) pcibr_config_get, (pciio_config_set_f *) pcibr_config_set, - (pciio_error_extract_f *) 0, + + (pciio_error_extract_f *) pcibr_error_extract, + (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback, (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback, (pciio_device_unregister_f *) pcibr_device_unregister, --- diff/arch/ia64/sn/io/sn2/shuberror.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/shuberror.c 2004-02-09 10:39:51.000000000 +0000 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include --- diff/arch/ia64/sn/io/sn2/xbow.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/xbow.c 2004-02-09 10:39:51.000000000 +0000 @@ -9,11 +9,15 @@ #include #include #include +#include +#include +#include #include #include #include #include #include +#include /* #define DEBUG 1 */ /* #define XBOW_DEBUG 1 */ --- diff/arch/ia64/sn/io/sn2/xtalk.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/sn2/xtalk.c 2004-02-09 10:39:51.000000000 +0000 @@ -30,9 +30,6 @@ * completely disappear. */ -#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) -#define DEL(ptr) (kfree(ptr)) - char widget_info_fingerprint[] = "widget_info"; /* ===================================================================== @@ -50,13 +47,10 @@ xtalk_dmamap_t xtalk_dmamap_alloc(vertex_hdl_t, device_desc_t, size_t, unsigned); void xtalk_dmamap_free(xtalk_dmamap_t); iopaddr_t xtalk_dmamap_addr(xtalk_dmamap_t, paddr_t, size_t); -alenlist_t xtalk_dmamap_list(xtalk_dmamap_t, alenlist_t, unsigned); void xtalk_dmamap_done(xtalk_dmamap_t); iopaddr_t xtalk_dmatrans_addr(vertex_hdl_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t xtalk_dmatrans_list(vertex_hdl_t, device_desc_t, alenlist_t, unsigned); void xtalk_dmamap_drain(xtalk_dmamap_t); void xtalk_dmaaddr_drain(vertex_hdl_t, iopaddr_t, size_t); -void xtalk_dmalist_drain(vertex_hdl_t, alenlist_t); xtalk_intr_t xtalk_intr_alloc(vertex_hdl_t, device_desc_t, vertex_hdl_t); xtalk_intr_t xtalk_intr_alloc_nothd(vertex_hdl_t, device_desc_t, vertex_hdl_t); void xtalk_intr_free(xtalk_intr_t); @@ -355,16 +349,6 @@ } -alenlist_t -xtalk_dmamap_list(xtalk_dmamap_t xtalk_dmamap, /* use these mapping resources */ - alenlist_t alenlist, /* map this Address/Length List */ - unsigned flags) -{ - return DMAMAP_FUNC(xtalk_dmamap, dmamap_list) - (CAST_DMAMAP(xtalk_dmamap), alenlist, flags); -} - - void xtalk_dmamap_done(xtalk_dmamap_t xtalk_dmamap) { @@ -385,16 +369,6 @@ } -alenlist_t -xtalk_dmatrans_list(vertex_hdl_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - alenlist_t palenlist, /* system address/length list */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_list) - (dev, dev_desc, palenlist, flags); -} - void xtalk_dmamap_drain(xtalk_dmamap_t map) { @@ -409,13 +383,6 @@ (dev, addr, size); } -void -xtalk_dmalist_drain(vertex_hdl_t dev, alenlist_t list) -{ - DEV_FUNC(dev, dmalist_drain) - (dev, list); -} - /* ===================================================================== * INTERRUPT MANAGEMENT * @@ -855,7 +822,9 @@ char *s,devnm[MAXDEVNAME]; /* Allocate widget_info and associate it with widget vertex */ - NEW(widget_info); + widget_info = kmalloc(sizeof(*widget_info), GFP_KERNEL); + if (!widget_info) + return - ENOMEM; /* Initialize widget_info */ widget_info->w_vertex = widget; @@ -898,16 +867,13 @@ /* Make sure that we have valid widget information initialized */ if (!(widget_info = xwidget_info_get(widget))) - return(1); + return 1; hwid = &(widget_info->w_hwid); - /* Clean out the xwidget information */ - (void)kfree(widget_info->w_name); - memset((void *)widget_info, 0, sizeof(widget_info)); - DEL(widget_info); - - return(0); + kfree(widget_info->w_name); + kfree(widget_info); + return 0; } void --- diff/arch/ia64/sn/io/xswitch.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/io/xswitch.c 2004-02-09 10:39:51.000000000 +0000 @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -18,8 +19,6 @@ #include #include -#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) -#define DEL(ptr) (kfree(ptr)) /* * This file provides generic support for Crosstalk @@ -118,7 +117,12 @@ if (xswitch_info == NULL) { int port; - NEW(xswitch_info); + xswitch_info = kmalloc(sizeof(*xswitch_info), GFP_KERNEL); + if (!xswitch_info) { + printk(KERN_WARNING "xswitch_info_new(): Unable to " + "allocate memory\n"); + return NULL; + } xswitch_info->census = 0; for (port = 0; port <= XSWITCH_CENSUS_PORT_MAX; port++) { xswitch_info_vhdl_set(xswitch_info, port, --- diff/arch/ia64/sn/kernel/bte.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/kernel/bte.c 2004-02-09 10:39:51.000000000 +0000 @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include #include #include --- diff/arch/ia64/sn/kernel/irq.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/kernel/irq.c 2004-02-09 10:39:51.000000000 +0000 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -40,8 +41,12 @@ extern void pcibr_force_interrupt(pcibr_intr_t intr); extern int sn_force_interrupt_flag; -static pcibr_intr_list_t *pcibr_intr_list; +struct sn_intr_list_t { + struct sn_intr_list_t *next; + pcibr_intr_t intr; +}; +static struct sn_intr_list_t *sn_intr_list[NR_IRQS]; static unsigned int @@ -114,30 +119,24 @@ } static void -sn_set_affinity_irq(unsigned int irq, cpumask_t mask) +sn_set_affinity_irq(unsigned int irq, unsigned long cpu) { -#if CONFIG_SMP - int redir = 0; - pcibr_intr_list_t p = pcibr_intr_list[irq]; - pcibr_intr_t intr; - int cpu; - extern void sn_shub_redirect_intr(pcibr_intr_t intr, unsigned long cpu); - extern void sn_tio_redirect_intr(pcibr_intr_t intr, unsigned long cpu); - +#if CONFIG_SMP + int redir = 0; + struct sn_intr_list_t *p = sn_intr_list[irq]; + pcibr_intr_t intr; + extern void sn_shub_redirect_intr(pcibr_intr_t intr, unsigned long cpu); + extern void sn_tio_redirect_intr(pcibr_intr_t intr, unsigned long cpu); + if (p == NULL) return; - intr = p->il_intr; + intr = p->intr; if (intr == NULL) return; - cpu = first_cpu(mask); - if (IS_PIC_SOFT(intr->bi_soft) ) { - sn_shub_redirect_intr(intr, cpu); - } else { - return; - } + sn_shub_redirect_intr(intr, cpu); (void) set_irq_affinity_info(irq, cpu_physical_id(intr->bi_cpu), redir); #endif /* CONFIG_SMP */ } @@ -156,7 +155,8 @@ struct irq_desc * -sn_irq_desc(unsigned int irq) { +sn_irq_desc(unsigned int irq) +{ irq = SN_IVEC_FROM_IRQ(irq); @@ -164,12 +164,14 @@ } u8 -sn_irq_to_vector(u8 irq) { +sn_irq_to_vector(u8 irq) +{ return(irq); } unsigned int -sn_local_vector_to_irq(u8 vector) { +sn_local_vector_to_irq(u8 vector) +{ return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector)); } @@ -179,7 +181,7 @@ int i; irq_desc_t *base_desc = _irq_desc; - for (i=IA64_FIRST_DEVICE_VECTOR; ibi_cpu; + if (pdacpu(cpu)->sn_last_irq < irq) { pdacpu(cpu)->sn_last_irq = irq; } - if (pdacpu(cpu)->sn_first_irq > irq) pdacpu(cpu)->sn_first_irq = irq; - if (!p) panic("Could not allocate memory for pcibr_intr_list_t\n"); - if ((list = pcibr_intr_list[irq])) { - while (list->il_next) list = list->il_next; - list->il_next = p; - p->il_next = NULL; - p->il_intr = intr; + if (pdacpu(cpu)->sn_first_irq == 0 || pdacpu(cpu)->sn_first_irq > irq) pdacpu(cpu)->sn_first_irq = irq; + if (!p) panic("Could not allocate memory for sn_intr_list_t\n"); + if ((list = sn_intr_list[irq])) { + while (list->next) list = list->next; + list->next = p; + p->next = NULL; + p->intr = intr; } else { - pcibr_intr_list[irq] = p; - p->il_next = NULL; - p->il_intr = intr; + sn_intr_list[irq] = p; + p->next = NULL; + p->intr = intr; } } void -force_polled_int(void) { +force_polled_int(void) +{ int i; - pcibr_intr_list_t p; + struct sn_intr_list_t *p; for (i=0; iil_intr){ - pcibr_force_interrupt(p->il_intr); + if (p->intr){ + pcibr_force_interrupt(p->intr); } - p = p->il_next; + p = p->next; } } } static void -force_interrupt(int irq) { - pcibr_intr_list_t p = pcibr_intr_list[irq]; +force_interrupt(int irq) +{ + struct sn_intr_list_t *p = sn_intr_list[irq]; while (p) { - if (p->il_intr) { - pcibr_force_interrupt(p->il_intr); + if (p->intr) { + pcibr_force_interrupt(p->intr); } - p = p->il_next; + p = p->next; } } @@ -255,14 +253,15 @@ */ static void -sn_check_intr(int irq, pcibr_intr_t intr) { +sn_check_intr(int irq, pcibr_intr_t intr) +{ unsigned long regval; int irr_reg_num; int irr_bit; unsigned long irr_reg; - regval = pcireg_intr_status_get(intr->bi_soft->bs_base); + regval = pcireg_intr_status_get(intr->bi_soft); irr_reg_num = irq_to_vector(irq) / 64; irr_bit = irq_to_vector(irq) % 64; switch (irr_reg_num) { @@ -294,68 +293,20 @@ } void -sn_lb_int_war_check(void) { +sn_lb_int_war_check(void) +{ int i; if (pda->sn_first_irq == 0) return; for (i=pda->sn_first_irq; i <= pda->sn_last_irq; i++) { - pcibr_intr_list_t p = pcibr_intr_list[i]; + struct sn_intr_list_t *p = sn_intr_list[i]; if (p == NULL) { continue; } while (p) { - sn_check_intr(i, p->il_intr); - p = p->il_next; + sn_check_intr(i, p->intr); + p = p->next; } } } - -static inline int -sn_get_next_bit(void) { - int i; - int bit; - - for (i = 3; i >= 0; i--) { - if (pda->sn_soft_irr[i] != 0) { - bit = (i * 64) + __ffs(pda->sn_soft_irr[i]); - __change_bit(bit, (volatile void *)pda->sn_soft_irr); - return(bit); - } - } - return IA64_SPURIOUS_INT_VECTOR; -} - -void -sn_set_tpr(int vector) { - if (vector > IA64_LAST_DEVICE_VECTOR || vector < IA64_FIRST_DEVICE_VECTOR) { - ia64_setreg(_IA64_REG_CR_TPR, vector); - } else { - ia64_setreg(_IA64_REG_CR_TPR, IA64_LAST_DEVICE_VECTOR); - } -} - -static inline void -sn_get_all_ivr(void) { - int vector; - - vector = ia64_get_ivr(); - while (vector != IA64_SPURIOUS_INT_VECTOR) { - __set_bit(vector, (volatile void *)pda->sn_soft_irr); - ia64_eoi(); - if (vector > IA64_LAST_DEVICE_VECTOR) return; - vector = ia64_get_ivr(); - } -} - -int -sn_get_ivr(void) { - int vector; - - vector = sn_get_next_bit(); - if (vector == IA64_SPURIOUS_INT_VECTOR) { - sn_get_all_ivr(); - vector = sn_get_next_bit(); - } - return vector; -} --- diff/arch/ia64/sn/kernel/mca.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/kernel/mca.c 2004-02-09 10:39:51.000000000 +0000 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include --- diff/arch/ia64/sn/kernel/probe.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/kernel/probe.c 2004-02-09 10:39:51.000000000 +0000 @@ -8,6 +8,7 @@ * Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ +#include #include /** --- diff/arch/ia64/sn/kernel/setup.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/kernel/setup.c 2004-02-09 10:39:51.000000000 +0000 @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -50,8 +51,6 @@ DEFINE_PER_CPU(struct pda_s, pda_percpu); -#define pxm_to_nasid(pxm) ((pxm)<<1) - #define MAX_PHYS_MEMORY (1UL << 49) /* 1 TB */ extern void bte_init_node (nodepda_t *, cnodeid_t); @@ -61,6 +60,8 @@ extern void init_platform_hubinfo(nodepda_t **nodepdaindr); extern void (*ia64_mark_idle)(int); extern void snidle(int); +extern unsigned char acpi_kbd_controller_present; + unsigned long sn_rtc_cycles_per_second; @@ -70,8 +71,7 @@ short physical_node_map[MAX_PHYSNODE_ID]; -int numionodes; - +int numionodes; /* * This is the address of the RRegs in the HSpace of the global * master. It is used by a hack in serial.c (serial_[in|out], @@ -120,6 +120,29 @@ char drive_info[4*16]; #endif +/* + * This routine can only be used during init, since + * smp_boot_data is an init data structure. + * We have to use smp_boot_data.cpu_phys_id to find + * the physical id of the processor because the normal + * cpu_physical_id() relies on data structures that + * may not be initialized yet. + */ + +static int +pxm_to_nasid(int pxm) +{ + int i; + int nid; + + nid = pxm_to_nid_map[pxm]; + for (i = 0; i < num_memblks; i++) { + if (node_memblk[i].nid == nid) { + return NASID_GET(node_memblk[i].start_paddr); + } + } + return -1; +} /** * early_sn_setup - early setup routine for SN platforms * @@ -223,6 +246,22 @@ extern void sn_cpu_init(void); extern nasid_t snia_get_console_nasid(void); + /* + * If the generic code has enabled vga console support - lets + * get rid of it again. This is a kludge for the fact that ACPI + * currtently has no way of informing us if legacy VGA is available + * or not. + */ +#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) + if (conswitchp == &vga_con) { + printk(KERN_DEBUG "SGI: Disabling VGA console\n"); +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#else + conswitchp = NULL; +#endif /* CONFIG_DUMMY_CONSOLE */ + } +#endif /* def(CONFIG_VT) && def(CONFIG_VGA_CONSOLE) */ MAX_DMA_ADDRESS = PAGE_OFFSET + MAX_PHYS_MEMORY; @@ -231,6 +270,19 @@ if (pxm_to_nid_map[pxm] != -1) physical_node_map[pxm_to_nasid(pxm)] = pxm_to_nid_map[pxm]; + + /* + * Old PROMs do not provide an ACPI FADT. Disable legacy keyboard + * support here so we don't have to listen to failed keyboard probe + * messages. + */ + if ((major < 2 || (major == 2 && minor <= 9)) && + acpi_kbd_controller_present) { + printk(KERN_INFO "Disabling legacy keyboard support as prom " + "is too old and doesn't provide FADT\n"); + acpi_kbd_controller_present = 0; + } + printk("SGI SAL version %x.%02x\n", major, minor); /* @@ -277,11 +329,6 @@ */ sn_init_pdas(cmdline_p); - /* - * Check for WARs. - */ - sn_check_for_wars(); - ia64_mark_idle = &snidle; /* @@ -340,7 +387,7 @@ /* * Now copy the array of nodepda pointers to each nodepda. */ - for (cnode=0; cnode < numnodes; cnode++) + for (cnode=0; cnode < numionodes; cnode++) memcpy(nodepdaindr[cnode]->pernode_pdaindr, nodepdaindr, sizeof(nodepdaindr)); @@ -371,7 +418,8 @@ int cpuphyid; int nasid; int slice; - int cnode, i; + int cnode; + static int wars_have_been_checked; /* * The boot cpu makes this call again after platform initialization is @@ -393,12 +441,24 @@ pda->hb_count = HZ/2; pda->hb_state = 0; pda->idle_flag = 0; + + if (cpuid != 0){ + memcpy(pda->cnodeid_to_nasid_table, pdacpu(0)->cnodeid_to_nasid_table, + sizeof(pda->cnodeid_to_nasid_table)); + } + + /* + * Check for WARs. + * Only needs to be done once, on BSP. + * Has to be done after loop above, because it uses pda.cnodeid_to_nasid_table[i]. + * Has to be done before assignment below. + */ + if (!wars_have_been_checked) { + sn_check_for_wars(); + wars_have_been_checked = 1; + } pda->shub_1_1_found = shub_1_1_found; - memset(pda->cnodeid_to_nasid_table, -1, sizeof(pda->cnodeid_to_nasid_table)); - for (i=0; icnodeid_to_nasid_table[i] = pxm_to_nasid(nid_to_pxm_map[i]); - if (local_node_data->active_cpu_count == 1) nodepda->node_first_cpu = cpuid; @@ -437,8 +497,10 @@ */ void -scan_for_ionodes(void) { +scan_for_ionodes(void) +{ int nasid = 0; + lboard_t *brd; /* Setup ionodes with memory */ for (nasid = 0; nasid < MAX_PHYSNODE_ID; nasid +=2) { @@ -450,12 +512,40 @@ klgraph_header = cnodeid = -1; klgraph_header = ia64_sn_get_klconfig_addr(nasid); - if (klgraph_header <= 0) + if (klgraph_header <= 0) { + if ( IS_RUNNING_ON_SIMULATOR() ) + continue; BUG(); /* All nodes must have klconfig tables! */ + } cnodeid = nasid_to_cnodeid(nasid); root_lboard[cnodeid] = (lboard_t *) NODE_OFFSET_TO_LBOARD( (nasid), ((kl_config_hdr_t *)(klgraph_header))-> ch_board_info); } + + /* Scan headless/memless IO Nodes. */ + for (nasid = 0; nasid < MAX_PHYSNODE_ID; nasid +=2) { + /* if there's no nasid, don't try to read the klconfig on the node */ + if (physical_node_map[nasid] == -1) continue; + brd = find_lboard_any((lboard_t *)root_lboard[nasid_to_cnodeid(nasid)], KLTYPE_SNIA); + if (brd) { + brd = KLCF_NEXT_ANY(brd); /* Skip this node's lboard */ + if (!brd) + continue; + } + + brd = find_lboard_any(brd, KLTYPE_SNIA); + while (brd) { + pda->cnodeid_to_nasid_table[numionodes] = brd->brd_nasid; + physical_node_map[brd->brd_nasid] = numionodes; + root_lboard[numionodes] = brd; + numionodes++; + brd = KLCF_NEXT_ANY(brd); + if (!brd) + break; + + brd = find_lboard_any(brd, KLTYPE_SNIA); + } + } } --- diff/arch/ia64/sn/kernel/sn2/io.c 2003-10-27 09:20:36.000000000 +0000 +++ source/arch/ia64/sn/kernel/sn2/io.c 2004-02-09 10:39:51.000000000 +0000 @@ -23,6 +23,10 @@ #undef __sn_readw #undef __sn_readl #undef __sn_readq +#undef __sn_readb_relaxed +#undef __sn_readw_relaxed +#undef __sn_readl_relaxed +#undef __sn_readq_relaxed unsigned int __sn_inb (unsigned long port) @@ -84,4 +88,28 @@ return ___sn_readq (addr); } +unsigned char +__sn_readb_relaxed (void *addr) +{ + return ___sn_readb_relaxed (addr); +} + +unsigned short +__sn_readw_relaxed (void *addr) +{ + return ___sn_readw_relaxed (addr); +} + +unsigned int +__sn_readl_relaxed (void *addr) +{ + return ___sn_readl_relaxed (addr); +} + +unsigned long +__sn_readq_relaxed (void *addr) +{ + return ___sn_readq_relaxed (addr); +} + #endif --- diff/arch/ia64/sn/kernel/sn2/prominfo_proc.c 2003-07-11 09:39:50.000000000 +0100 +++ source/arch/ia64/sn/kernel/sn2/prominfo_proc.c 2004-02-09 10:39:51.000000000 +0000 @@ -14,6 +14,7 @@ #include #include #include +#include #include /* to lookup nasids */ --- diff/arch/ia64/sn/kernel/sn2/sn2_smp.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/kernel/sn2/sn2_smp.c 2004-02-09 10:39:51.000000000 +0000 @@ -21,6 +21,7 @@ #include #include +#include #include #include #include --- diff/arch/ia64/sn/kernel/sn2/sn_proc_fs.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ia64/sn/kernel/sn2/sn_proc_fs.c 2004-02-09 10:39:51.000000000 +0000 @@ -10,6 +10,7 @@ #ifdef CONFIG_PROC_FS #include +#include #include --- diff/arch/m68k/Kconfig 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/m68k/Kconfig 2004-02-09 10:39:51.000000000 +0000 @@ -1073,8 +1073,7 @@ precision in some cases. To compile this driver as a module, choose M here: the - module will be called genrtc. To load the module automatically - add 'alias char-major-10-135 genrtc' to your /etc/modules.conf + module will be called genrtc. config GEN_RTC_X bool "Extended RTC operation" --- diff/arch/mips/kernel/sysirix.c 2003-09-30 15:46:11.000000000 +0100 +++ source/arch/mips/kernel/sysirix.c 2004-02-09 10:39:51.000000000 +0000 @@ -368,7 +368,7 @@ retval = HZ; goto out; case 4: - retval = NGROUPS; + retval = NGROUPS_MAX; goto out; case 5: retval = NR_OPEN; --- diff/arch/ppc/8260_io/enet.c 2003-09-30 15:46:11.000000000 +0100 +++ source/arch/ppc/8260_io/enet.c 2004-02-09 10:39:51.000000000 +0000 @@ -851,7 +851,7 @@ err = register_netdev(dev); if (err) { - kfree(dev); + free_netdev(dev); return err; } --- diff/arch/ppc/8260_io/fcc_enet.c 2003-09-30 15:46:11.000000000 +0100 +++ source/arch/ppc/8260_io/fcc_enet.c 2004-02-09 10:39:51.000000000 +0000 @@ -1371,7 +1371,7 @@ err = register_netdev(dev); if (err) { - kfree(dev); + free_netdev(dev); return err; } --- diff/arch/ppc/8xx_io/enet.c 2003-09-30 15:46:11.000000000 +0100 +++ source/arch/ppc/8xx_io/enet.c 2004-02-09 10:39:51.000000000 +0000 @@ -949,7 +949,7 @@ err = register_netdev(dev); if (err) { - kfree(dev); + free_netdev(dev); return err; } --- diff/arch/ppc/8xx_io/fec.c 2003-06-30 10:07:19.000000000 +0100 +++ source/arch/ppc/8xx_io/fec.c 2004-02-09 10:39:51.000000000 +0000 @@ -1748,7 +1748,7 @@ err = register_netdev(dev); if (err) { - kfree(dev); + free_netdev(dev); return err; } --- diff/arch/ppc/Kconfig 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ppc/Kconfig 2004-02-09 10:39:51.000000000 +0000 @@ -30,6 +30,10 @@ bool default y +# All PPCs use generic nvram driver through ppc_md +config GENERIC_NVRAM + bool + default y source "init/Kconfig" @@ -181,7 +185,7 @@ config PPC601_SYNC_FIX bool "Workarounds for PPC601 bugs" - depends on 6xx + depends on 6xx && (PPC_PREP || PPC_PMAC) help Some versions of the PPC601 (the first PowerPC chip) have bugs which mean that extra synchronization instructions are required near @@ -583,11 +587,6 @@ depends on PPC_MULTIPLATFORM default y -config PPC_GEN550 - bool - depends on SANDPOINT - default y - config PPC_PMAC bool depends on PPC_MULTIPLATFORM @@ -603,6 +602,11 @@ depends on PPC_PMAC || PPC_CHRP default y +config PPC_GEN550 + bool + depends on SANDPOINT || MCPN765 + default y + config FORCE bool depends on 6xx && (PCORE || POWERPMC250) @@ -989,8 +993,6 @@ source "drivers/pcmcia/Kconfig" -source "drivers/parport/Kconfig" - endmenu menu "Advanced setup" @@ -1088,179 +1090,10 @@ depends on ADVANCED_OPTIONS && 8xx endmenu -source "drivers/base/Kconfig" - -source "drivers/mtd/Kconfig" - -source "drivers/pnp/Kconfig" - -source "drivers/block/Kconfig" - -source "drivers/md/Kconfig" - -source "drivers/ide/Kconfig" - -source "drivers/scsi/Kconfig" - -source "drivers/message/fusion/Kconfig" - -source "drivers/ieee1394/Kconfig" - -source "drivers/message/i2o/Kconfig" - -source "net/Kconfig" - -source "drivers/isdn/Kconfig" - -source "drivers/video/Kconfig" - -source "drivers/cdrom/Kconfig" - -source "drivers/input/Kconfig" - - -menu "Macintosh device drivers" - -# we want to change this to something like CONFIG_SYSCTRL_CUDA/PMU -config ADB_CUDA - bool "Support for CUDA based PowerMacs" - depends on PPC_PMAC - help - This provides support for CUDA based Power Macintosh systems. This - includes most OldWorld PowerMacs, the first generation iMacs, the - Blue&White G3 and the "Yikes" G4 (PCI Graphics). All later models - should use CONFIG_ADB_PMU instead. It is safe to say Y here even if - your machine doesn't have a CUDA. - - If unsure say Y. - -config ADB_PMU - bool "Support for PMU based PowerMacs" - depends on PPC_PMAC - help - On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the - PMU is an embedded microprocessor whose primary function is to - control system power, and battery charging on the portable models. - The PMU also controls the ADB (Apple Desktop Bus) which connects to - the keyboard and mouse on some machines, as well as the non-volatile - RAM and the RTC (real time clock) chip. Say Y to enable support for - this device; you should do so if your machine is one of those - mentioned above. - -config PMAC_PBOOK - bool "Power management support for PowerBooks" - depends on ADB_PMU - ---help--- - This provides support for putting a PowerBook to sleep; it also - enables media bay support. Power management works on the - PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3 and - the Titanium Powerbook G4, as well as the iBooks. You should get - the power management daemon, pmud, to make it work and you must have - the /dev/pmu device (see the pmud README). - - Get pmud from . - - If you have a PowerBook, you should say Y here. - - You may also want to compile the dma sound driver as a module and - have it autoloaded. The act of removing the module shuts down the - sound hardware for more power savings. - -config PM - bool - depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK - default y - -config PMAC_APM_EMU - tristate "APM emulation" - depends on PMAC_PBOOK - -# made a separate option since backlight may end up beeing used -# on non-powerbook machines (but only on PMU based ones AFAIK) -config PMAC_BACKLIGHT - bool "Backlight control for LCD screens" - depends on ADB_PMU - help - Say Y here to build in code to manage the LCD backlight on a - Macintosh PowerBook. With this code, the backlight will be turned - on and off appropriately on power-management and lid-open/lid-closed - events; also, the PowerBook button device will be enabled so you can - change the screen brightness. - -config MAC_FLOPPY - bool "Support for PowerMac floppy" - depends on PPC_PMAC - help - If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple) - floppy controller, say Y here. Most commonly found in PowerMacs. - -config MAC_SERIAL - tristate "Support for PowerMac serial ports (OBSOLETE DRIVER)" - depends on PPC_PMAC - help - This driver is obsolete. Use CONFIG_SERIAL_PMACZILOG in - "Character devices --> Serial drivers --> PowerMac z85c30" option. - -config ADB - bool "Apple Desktop Bus (ADB) support" - depends on PPC_PMAC - help - Apple Desktop Bus (ADB) support is for support of devices which - are connected to an ADB port. ADB devices tend to have 4 pins. - If you have an Apple Macintosh prior to the iMac, an iBook or - PowerBook, or a "Blue and White G3", you probably want to say Y - here. Otherwise say N. - -config ADB_MACIO - bool "Include MacIO (CHRP) ADB driver" - depends on ADB - help - Say Y here to include direct support for the ADB controller in the - Hydra chip used on PowerPC Macintoshes of the CHRP type. (The Hydra - also includes a MESH II SCSI controller, DBDMA controller, VIA chip, - OpenPIC controller and two RS422/Geoports.) - -config INPUT_ADBHID - bool "Support for ADB input devices (keyboard, mice, ...)" - depends on ADB && INPUT=y - help - Say Y here if you want to have ADB (Apple Desktop Bus) HID devices - such as keyboards, mice, joysticks, trackpads or graphic tablets - handled by the input layer. If you say Y here, make sure to say Y to - the corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV), - "Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface - support" (CONFIG_INPUT_EVDEV) as well. - - If unsure, say Y. - -config MAC_EMUMOUSEBTN - bool "Support for mouse button 2+3 emulation" - depends on INPUT_ADBHID - help - This provides generic support for emulating the 2nd and 3rd mouse - button with keypresses. If you say Y here, the emulation is still - disabled by default. The emulation is controlled by these sysctl - entries: - /proc/sys/dev/mac_hid/mouse_button_emulation - /proc/sys/dev/mac_hid/mouse_button2_keycode - /proc/sys/dev/mac_hid/mouse_button3_keycode - - If you have an Apple machine with a 1-button mouse, say Y here. - -config ANSLCD - bool "Support for ANS LCD display" - depends on ADB_CUDA - -endmenu - -source "drivers/char/Kconfig" - -source "drivers/media/Kconfig" +source "drivers/Kconfig" source "fs/Kconfig" -source "sound/Kconfig" - source "arch/ppc/8xx_io/Kconfig" source "arch/ppc/8260_io/Kconfig" @@ -1285,8 +1118,6 @@ endmenu -source "drivers/usb/Kconfig" - source "lib/Kconfig" @@ -1404,7 +1235,7 @@ config SERIAL_TEXT_DEBUG bool "Support for early boot texts over serial port" - depends on 4xx || GT64260 || LOPEC || MCPN765 || PPLUS || PRPMC800 || SANDPOINT + depends on 4xx || GT64260 || LOPEC || PPLUS || PRPMC800 || PPC_GEN550 config OCP bool --- diff/arch/ppc/boot/ld.script 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/ppc/boot/ld.script 2004-02-09 10:39:51.000000000 +0000 @@ -82,6 +82,7 @@ *(__ksymtab) *(__ksymtab_strings) *(__bug_table) + *(__kcrctab) } } --- diff/arch/ppc/configs/pmac_defconfig 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/ppc/configs/pmac_defconfig 2004-02-09 10:39:51.000000000 +0000 @@ -6,13 +6,15 @@ CONFIG_HAVE_DEC_LOCK=y CONFIG_PPC=y CONFIG_PPC32=y +CONFIG_GENERIC_NVRAM=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y +# CONFIG_CLEAN_COMPILE is not set # CONFIG_STANDALONE is not set +CONFIG_BROKEN=y CONFIG_BROKEN_ON_SMP=y # @@ -23,8 +25,7 @@ # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y +# CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y CONFIG_FUTEX=y @@ -32,6 +33,7 @@ CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # # Loadable module support @@ -53,16 +55,15 @@ # CONFIG_POWER4 is not set # CONFIG_8xx is not set CONFIG_ALTIVEC=y -CONFIG_TAU=y -# CONFIG_TAU_INT is not set -# CONFIG_TAU_AVERAGE is not set +# CONFIG_TAU is not set CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_PROC_INTF=y CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set -# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_24_API=y CONFIG_CPU_FREQ_PMAC=y CONFIG_CPU_FREQ_TABLE=y CONFIG_PPC601_SYNC_FIX=y @@ -101,7 +102,7 @@ CONFIG_PPCBUG_NVRAM=y # CONFIG_SMP is not set # CONFIG_PREEMPT is not set -# CONFIG_HIGHMEM is not set +CONFIG_HIGHMEM=y CONFIG_KERNEL_ELF=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m @@ -131,14 +132,10 @@ CONFIG_TCIC=m # -# Parallel port support -# -# CONFIG_PARPORT is not set - -# # Advanced setup # CONFIG_ADVANCED_OPTIONS=y +# CONFIG_HIGHMEM_START_BOOL is not set CONFIG_HIGHMEM_START=0xfe000000 # CONFIG_LOWMEM_SIZE_BOOL is not set CONFIG_LOWMEM_SIZE=0x30000000 @@ -149,6 +146,10 @@ CONFIG_BOOT_LOAD=0x00800000 # +# Device Drivers +# + +# # Generic Driver Options # # CONFIG_FW_LOADER is not set @@ -159,6 +160,11 @@ # CONFIG_MTD is not set # +# Parallel port support +# +# CONFIG_PARPORT is not set + +# # Plug and Play support # # CONFIG_PNP is not set @@ -166,6 +172,7 @@ # # Block devices # +# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set @@ -179,11 +186,6 @@ CONFIG_LBD=y # -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# # ATA/ATAPI/MFM/RLL support # CONFIG_IDE=y @@ -213,7 +215,6 @@ # CONFIG_BLK_DEV_OPTI621 is not set CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDEDMA_PCI=y -# CONFIG_BLK_DEV_IDE_TCQ is not set # CONFIG_BLK_DEV_IDEDMA_FORCED is not set CONFIG_IDEDMA_PCI_AUTO=y # CONFIG_IDEDMA_ONLYDISK is not set @@ -284,15 +285,16 @@ CONFIG_SCSI_AIC7XXX=m CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 CONFIG_AIC7XXX_RESET_DELAY_MS=15000 -# CONFIG_AIC7XXX_PROBE_EISA_VL is not set # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set CONFIG_AIC7XXX_DEBUG_ENABLE=y CONFIG_AIC7XXX_DEBUG_MASK=0 CONFIG_AIC7XXX_REG_PRETTY_PRINT=y CONFIG_SCSI_AIC7XXX_OLD=m # CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_DPT_I2O is not set CONFIG_SCSI_ADVANSYS=m # CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_SATA is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set @@ -301,16 +303,24 @@ # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set +CONFIG_SCSI_QLA2XXX_CONFIG=y +# CONFIG_SCSI_QLA21XX is not set +# CONFIG_SCSI_QLA22XX is not set +# CONFIG_SCSI_QLA23XX is not set # CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set CONFIG_SCSI_MESH=y @@ -327,6 +337,11 @@ # CONFIG_PCMCIA_QLOGIC is not set # +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# # Fusion MPT device support # # CONFIG_FUSION is not set @@ -340,15 +355,12 @@ # Subsystem Options # # CONFIG_IEEE1394_VERBOSEDEBUG is not set -# CONFIG_IEEE1394_OUI_DB is not set +CONFIG_IEEE1394_OUI_DB=y # # Device Drivers # - -# -# Texas Instruments PCILynx requires I2C bit-banging -# +CONFIG_IEEE1394_PCILYNX=m CONFIG_IEEE1394_OHCI1394=m # @@ -368,6 +380,23 @@ # CONFIG_I2O is not set # +# Macintosh device drivers +# +CONFIG_ADB_CUDA=y +CONFIG_ADB_PMU=y +CONFIG_PMAC_PBOOK=y +CONFIG_PMAC_APM_EMU=y +CONFIG_PMAC_BACKLIGHT=y +# CONFIG_MAC_FLOPPY is not set +# CONFIG_MAC_SERIAL is not set +CONFIG_ADB=y +CONFIG_ADB_MACIO=y +CONFIG_INPUT_ADBHID=y +CONFIG_MAC_EMUMOUSEBTN=y +# CONFIG_THERM_WINDTUNNEL is not set +# CONFIG_ANSLCD is not set + +# # Networking support # CONFIG_NET=y @@ -513,10 +542,11 @@ # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set CONFIG_NET_PCI=y -CONFIG_PCNET32=y +# CONFIG_PCNET32 is not set # CONFIG_AMD8111_ETH is not set # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set # CONFIG_DGRS is not set # CONFIG_EEPRO100 is not set # CONFIG_E100 is not set @@ -543,7 +573,7 @@ # CONFIG_R8169 is not set # CONFIG_SIS190 is not set # CONFIG_SK98LIN is not set -# CONFIG_TIGON3 is not set +CONFIG_TIGON3=y # # Ethernet (10000 Mbit) @@ -557,8 +587,8 @@ CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=m CONFIG_PPP_DEFLATE=y -CONFIG_PPP_BSDCOMP=m -# CONFIG_PPPOE is not set +CONFIG_PPP_BSDCOMP=y +CONFIG_PPPOE=m # CONFIG_SLIP is not set # @@ -689,58 +719,9 @@ # CONFIG_ISDN_BOOL is not set # -# Graphics support +# Telephony Support # -CONFIG_FB=y -# CONFIG_FB_CYBER2000 is not set -CONFIG_FB_OF=y -CONFIG_FB_CONTROL=y -CONFIG_FB_PLATINUM=y -CONFIG_FB_VALKYRIE=y -CONFIG_FB_CT65550=y -CONFIG_FB_IMSTT=y -# CONFIG_FB_S3TRIO is not set -# CONFIG_FB_VGA16 is not set -# CONFIG_FB_RIVA is not set -CONFIG_FB_MATROX=y -CONFIG_FB_MATROX_MILLENIUM=y -CONFIG_FB_MATROX_MYSTIQUE=y -# CONFIG_FB_MATROX_G450 is not set -CONFIG_FB_MATROX_G100A=y -CONFIG_FB_MATROX_G100=y -# CONFIG_FB_MATROX_MULTIHEAD is not set -CONFIG_FB_RADEON=y -CONFIG_FB_ATY128=y -CONFIG_FB_ATY=y -CONFIG_FB_ATY_CT=y -CONFIG_FB_ATY_GX=y -# CONFIG_FB_ATY_XL_INIT is not set -# CONFIG_FB_SIS is not set -# CONFIG_FB_NEOMAGIC is not set -CONFIG_FB_3DFX=y -# CONFIG_FB_VOODOO1 is not set -# CONFIG_FB_TRIDENT is not set -# CONFIG_FB_VIRTUAL is not set - -# -# Console display driver support -# -# CONFIG_VGA_CONSOLE is not set -# CONFIG_MDA_CONSOLE is not set -CONFIG_DUMMY_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_PCI_CONSOLE=y -# CONFIG_FONTS is not set -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y - -# -# Logo configuration -# -CONFIG_LOGO=y -CONFIG_LOGO_LINUX_MONO=y -CONFIG_LOGO_LINUX_VGA16=y -CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_PHONE is not set # # Input device support @@ -764,11 +745,8 @@ # # CONFIG_GAMEPORT is not set CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y +# CONFIG_SERIO is not set # CONFIG_SERIO_I8042 is not set -# CONFIG_SERIO_SERPORT is not set -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_PCIPS2 is not set # # Input Device Drivers @@ -786,22 +764,6 @@ # CONFIG_INPUT_MISC is not set # -# Macintosh device drivers -# -CONFIG_ADB_CUDA=y -CONFIG_ADB_PMU=y -CONFIG_PMAC_PBOOK=y -CONFIG_PMAC_APM_EMU=y -CONFIG_PMAC_BACKLIGHT=y -# CONFIG_MAC_FLOPPY is not set -CONFIG_MAC_SERIAL=y -CONFIG_ADB=y -CONFIG_ADB_MACIO=y -CONFIG_INPUT_ADBHID=y -CONFIG_MAC_EMUMOUSEBTN=y -# CONFIG_ANSLCD is not set - -# # Character devices # CONFIG_VT=y @@ -821,56 +783,16 @@ # Non-8250 serial port support # CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_PMACZILOG=y -# CONFIG_SERIAL_PMACZILOG_CONSOLE is not set +CONFIG_SERIAL_PMACZILOG_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 # -# I2C support -# -CONFIG_I2C=m -CONFIG_I2C_CHARDEV=m - -# -# I2C Algorithms -# -# CONFIG_I2C_ALGOBIT is not set -# CONFIG_I2C_ALGOPCF is not set - -# -# I2C Hardware Bus support -# -# CONFIG_I2C_ALI1535 is not set -# CONFIG_I2C_ALI15X3 is not set -# CONFIG_I2C_AMD756 is not set -# CONFIG_I2C_AMD8111 is not set -# CONFIG_I2C_I801 is not set -CONFIG_I2C_KEYWEST=m -# CONFIG_I2C_NFORCE2 is not set -# CONFIG_I2C_PIIX4 is not set -# CONFIG_I2C_SIS5595 is not set -# CONFIG_I2C_SIS630 is not set -# CONFIG_I2C_SIS96X is not set -# CONFIG_I2C_VIAPRO is not set - -# -# I2C Hardware Sensors Chip support -# -# CONFIG_I2C_SENSOR is not set -# CONFIG_SENSORS_ADM1021 is not set -# CONFIG_SENSORS_EEPROM is not set -# CONFIG_SENSORS_IT87 is not set -# CONFIG_SENSORS_LM75 is not set -# CONFIG_SENSORS_LM78 is not set -# CONFIG_SENSORS_LM85 is not set -# CONFIG_SENSORS_VIA686A is not set -# CONFIG_SENSORS_W83781D is not set - -# # Mice # -CONFIG_BUSMOUSE=y +# CONFIG_BUSMOUSE is not set # CONFIG_QIC02_TAPE is not set # @@ -884,7 +806,7 @@ # CONFIG_WATCHDOG is not set CONFIG_NVRAM=y CONFIG_GEN_RTC=y -# CONFIG_GEN_RTC_X is not set +CONFIG_GEN_RTC_X=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -893,8 +815,15 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set +CONFIG_AGP=m +CONFIG_AGP_UNINORTH=m +CONFIG_DRM=y +# CONFIG_DRM_TDFX is not set +# CONFIG_DRM_GAMMA is not set +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +# CONFIG_DRM_MGA is not set +# CONFIG_DRM_SIS is not set # # PCMCIA character devices @@ -903,167 +832,131 @@ # CONFIG_RAW_DRIVER is not set # -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices +# I2C support # -# CONFIG_DVB is not set +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y # -# File systems +# I2C Algorithms # -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_XATTR=y -# CONFIG_EXT3_FS_POSIX_ACL is not set -# CONFIG_EXT3_FS_SECURITY is not set -CONFIG_JBD=y -# CONFIG_JBD_DEBUG is not set -CONFIG_FS_MBCACHE=y -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -# CONFIG_XFS_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_ALGOPCF is not set # -# CD-ROM/DVD Filesystems +# I2C Hardware Bus support # -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_ZISOFS is not set -# CONFIG_UDF_FS is not set +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_ISA is not set +CONFIG_I2C_KEYWEST=m +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set # -# DOS/FAT/NT Filesystems +# I2C Hardware Sensors Chip support # -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m -# CONFIG_NTFS_FS is not set +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set # -# Pseudo filesystems +# Multimedia devices # -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_DEVFS_FS=y -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -# CONFIG_DEVPTS_FS_XATTR is not set -CONFIG_TMPFS=y -# CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y +# CONFIG_VIDEO_DEV is not set # -# Miscellaneous filesystems +# Digital Video Broadcasting Devices # -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=m -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set +# CONFIG_DVB is not set # -# Network File Systems +# Graphics support # -CONFIG_NFS_FS=y -# CONFIG_NFS_V3 is not set -# CONFIG_NFS_V4 is not set -CONFIG_NFSD=y -# CONFIG_NFSD_V3 is not set -# CONFIG_NFSD_TCP is not set -CONFIG_LOCKD=y -CONFIG_EXPORTFS=y -CONFIG_SUNRPC=y -# CONFIG_SUNRPC_GSS is not set -CONFIG_SMB_FS=m -# CONFIG_SMB_NLS_DEFAULT is not set -# CONFIG_CIFS is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set -# CONFIG_AFS_FS is not set +CONFIG_FB=y +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +CONFIG_FB_OF=y +CONFIG_FB_CONTROL=y +CONFIG_FB_PLATINUM=y +CONFIG_FB_VALKYRIE=y +CONFIG_FB_CT65550=y +CONFIG_FB_IMSTT=y +# CONFIG_FB_S3TRIO is not set +# CONFIG_FB_VGA16 is not set +CONFIG_FB_RIVA=y +CONFIG_FB_MATROX=y +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +# CONFIG_FB_MATROX_G450 is not set +CONFIG_FB_MATROX_G100A=y +CONFIG_FB_MATROX_G100=y +# CONFIG_FB_MATROX_I2C is not set +# CONFIG_FB_MATROX_MULTIHEAD is not set +CONFIG_FB_RADEON=y +CONFIG_FB_ATY128=y +CONFIG_FB_ATY=y +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GX=y +# CONFIG_FB_ATY_XL_INIT is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +CONFIG_FB_3DFX=y +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_VIRTUAL is not set # -# Partition Types +# Console display driver support # -CONFIG_PARTITION_ADVANCED=y -# CONFIG_ACORN_PARTITION is not set -# CONFIG_OSF_PARTITION is not set -# CONFIG_AMIGA_PARTITION is not set -# CONFIG_ATARI_PARTITION is not set -CONFIG_MAC_PARTITION=y -CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_MINIX_SUBPARTITION is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set -# CONFIG_LDM_PARTITION is not set -# CONFIG_NEC98_PARTITION is not set -# CONFIG_SGI_PARTITION is not set -# CONFIG_ULTRIX_PARTITION is not set -# CONFIG_SUN_PARTITION is not set -# CONFIG_EFI_PARTITION is not set -CONFIG_SMB_NLS=y -CONFIG_NLS=y +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y # -# Native Language Support +# Logo configuration # -CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1250 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -CONFIG_NLS_ISO8859_1=m -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y # # Sound @@ -1164,7 +1057,7 @@ # # CONFIG_USB_EHCI_HCD is not set CONFIG_USB_OHCI_HCD=y -# CONFIG_USB_UHCI_HCD is not set +CONFIG_USB_UHCI_HCD=y # # USB Device Class drivers @@ -1234,8 +1127,20 @@ # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_EDGEPORT_TI is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y # CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_KOBIL_SCT is not set # CONFIG_USB_SERIAL_MCT_U232 is not set @@ -1244,19 +1149,176 @@ # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set +CONFIG_USB_EZUSB=y # # USB Miscellaneous drivers # +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set # CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set # CONFIG_USB_TEST is not set # CONFIG_USB_GADGET is not set # +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS=y +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_HFS_FS=y +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=y +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_LOCKD=y +CONFIG_EXPORTFS=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_GSS is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_NEC98_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# # Library routines # CONFIG_CRC32=y @@ -1266,7 +1328,16 @@ # # Kernel hacking # -# CONFIG_DEBUG_KERNEL is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_DEBUG_INFO is not set CONFIG_BOOTX_TEXT=y # --- diff/arch/ppc/kernel/Makefile 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ppc/kernel/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -22,11 +22,12 @@ semaphore.o syscalls.o setup.o \ cputable.o ppc_htab.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o +obj-$(CONFIG_POWER4) += cpu_setup_power4.o obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_PCI) += pci-dma.o obj-$(CONFIG_KGDB) += ppc-stub.o -obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_SMP) += smp.o smp-tbsync.o obj-$(CONFIG_TAU) += temp.o ifdef CONFIG_MATH_EMULATION --- diff/arch/ppc/kernel/cpu_setup_6xx.S 2003-10-27 09:20:37.000000000 +0000 +++ source/arch/ppc/kernel/cpu_setup_6xx.S 2004-02-09 10:39:51.000000000 +0000 @@ -142,7 +142,7 @@ sync isync blr - + /* 740/750/7400/7410 * Enable Store Gathering (SGE), Address Brodcast (ABE), * Branch History Table (BHTE), Branch Target ICache (BTIC) @@ -213,7 +213,7 @@ li r7,CPU_FTR_CAN_NAP andc r6,r6,r7 stw r6,CPU_SPEC_FEATURES(r5) -1: +1: mfspr r11,HID0 /* All of the bits we have to set..... @@ -248,20 +248,21 @@ /* Definitions for the table use to save CPU states */ #define CS_HID0 0 #define CS_HID1 4 -#define CS_MSSCR0 8 -#define CS_MSSSR0 12 -#define CS_ICTRL 16 -#define CS_LDSTCR 20 -#define CS_LDSTDB 24 -#define CS_SIZE 28 +#define CS_HID2 8 +#define CS_MSSCR0 12 +#define CS_MSSSR0 16 +#define CS_ICTRL 20 +#define CS_LDSTCR 24 +#define CS_LDSTDB 28 +#define CS_SIZE 32 .data .balign L1_CACHE_LINE_SIZE -cpu_state_storage: +cpu_state_storage: .space CS_SIZE .balign L1_CACHE_LINE_SIZE,0 .text - + /* Called in normal context to backup CPU 0 state. This * does not include cache settings. This function is also * called for machine sleep. This does not include the MMU @@ -311,11 +312,18 @@ stw r4,CS_LDSTCR(r5) mfspr r4,SPRN_LDSTDB stw r4,CS_LDSTDB(r5) -1: +1: bne cr5,1f /* Backup 750FX specific registers */ mfspr r4,SPRN_HID1 stw r4,CS_HID1(r5) + /* If rev 2.x, backup HID2 */ + mfspr r3,PVR + andi. r3,r3,0xff00 + cmpi cr0,r3,0x0200 + bne 1f + mfspr r4,SPRN_HID2 + stw r4,CS_HID2(r5) 1: mtcr r7 blr @@ -395,9 +403,19 @@ sync 2: bne cr5,1f /* Restore 750FX specific registers - * that is restore PLL config & switch - * to PLL 0 + * that is restore HID2 on rev 2.x and PLL config & switch + * to PLL 0 on all */ + /* If rev 2.x, restore HID2 with low voltage bit cleared */ + mfspr r3,PVR + andi. r3,r3,0xff00 + cmpi cr0,r3,0x0200 + bne 4f + lwz r4,CS_HID2(r5) + rlwinm r4,r4,0,19,17 + mtspr SPRN_HID2,r4 + sync +4: lwz r4,CS_HID1(r5) rlwinm r5,r4,0,16,14 mtspr SPRN_HID1,r5 --- diff/arch/ppc/kernel/head.S 2003-10-27 09:20:37.000000000 +0000 +++ source/arch/ppc/kernel/head.S 2004-02-09 10:39:51.000000000 +0000 @@ -141,17 +141,6 @@ mr r27,r7 li r24,0 /* cpu # */ -#ifdef CONFIG_POWER4 -/* - * On the PPC970, we have to turn off real-mode cache inhibit - * early, before we first turn the MMU off. - */ - mfspr r0,SPRN_PVR - srwi r0,r0,16 - cmpwi r0,0x39 - beql ppc970_setup_hid -#endif /* CONFIG_POWER4 */ - /* * early_init() does the early machine identification and does * the necessary low-level setup and clears the BSS @@ -159,6 +148,14 @@ */ bl early_init +/* + * On POWER4, we first need to tweak some CPU configuration registers + * like real mode cache inhibit or exception base + */ +#ifdef CONFIG_POWER4 + bl __power4_cpu_preinit +#endif /* CONFIG_POWER4 */ + #ifdef CONFIG_APUS /* On APUS the __va/__pa constants need to be set to the correct * values before continuing. @@ -1216,7 +1213,7 @@ __secondary_start: #ifdef CONFIG_PPC64BRIDGE mfmsr r0 - clrldi r0,r0,1 /* make sure it's in 32-bit mode */ + clrldi r0,r0,1 /* make sure it's in 32-bit mode */ SYNC MTMSRD(r0) isync @@ -1278,26 +1275,15 @@ */ _GLOBAL(__setup_cpu_power3) blr -_GLOBAL(__setup_cpu_power4) - blr -_GLOBAL(__setup_cpu_ppc970) - blr _GLOBAL(__setup_cpu_generic) blr -#ifndef CONFIG_6xx +#if !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) _GLOBAL(__save_cpu_setup) blr _GLOBAL(__restore_cpu_setup) -#ifdef CONFIG_POWER4 - /* turn off real-mode cache inhibit on the PPC970 */ - mfspr r0,SPRN_PVR - srwi r0,r0,16 - cmpwi r0,0x39 - beq ppc970_setup_hid -#endif blr -#endif /* CONFIG_6xx */ +#endif /* !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) */ /* @@ -1633,10 +1619,14 @@ lis r4,0x2000 /* set pseudo-segment reg 12 */ ori r5,r4,0x0ccc mtsr 12,r5 +#if 0 ori r5,r4,0x0888 /* set pseudo-segment reg 8 */ mtsr 8,r5 /* (for access to serial port) */ - ori r5,r4,0x0999 /* set pseudo-segment reg 8 */ +#endif +#ifdef CONFIG_BOOTX_TEXT + ori r5,r4,0x0999 /* set pseudo-segment reg 9 */ mtsr 9,r5 /* (for access to screen) */ +#endif mfmsr r0 clrldi r0,r0,1 sync @@ -1644,43 +1634,8 @@ isync blr -/* - * On 970 (G5), we pre-set a few bits in HID0 & HID1 - */ -ppc970_setup_hid: - li r0,0 - sync - mtspr 0x3f4,r0 - isync - sync - mtspr 0x3f6,r0 - isync - mfspr r0,SPRN_HID0 - li r11,1 /* clear DOZE, NAP and SLEEP */ - rldimi r0,r11,52,8 /* set DPM */ - mtspr SPRN_HID0,r0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - sync - isync - mfspr r0,SPRN_HID1 - li r11,0x1200 /* enable i-fetch cacheability */ - sldi r11,r11,44 /* and prefetch */ - or r0,r0,r11 - mtspr SPRN_HID1,r0 - mtspr SPRN_HID1,r0 - isync - li r0,0 - sync - mtspr 0x137,0 - isync - blr #endif /* CONFIG_POWER4 */ - + #ifdef CONFIG_8260 /* Jump into the system reset for the rom. * We first disable the MMU, and then jump to the ROM reset address. --- diff/arch/ppc/kernel/idle_power4.S 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/ppc/kernel/idle_power4.S 2004-02-09 10:39:51.000000000 +0000 @@ -28,17 +28,11 @@ /* * Init idle, called at early CPU setup time from head.S for each CPU - * Make sure no rest of NAP mode remains in HID0, save default - * values for some CPU specific registers. Called with r24 - * containing CPU number and r3 reloc offset + * So nothing for now. Called with r24 containing CPU number and r3 + * reloc offset */ .globl init_idle_power4 init_idle_power4: -BEGIN_FTR_SECTION - mfspr r4,SPRN_HID0 - rlwinm r4,r4,0,10,8 /* Clear NAP */ - mtspr SPRN_HID0, r4 -END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) blr /* @@ -48,10 +42,9 @@ */ .globl power4_idle power4_idle: - /* Check if we can nap or doze, put HID0 mask in r3 - */ - lis r3, 0 BEGIN_FTR_SECTION + blr +END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) /* We must dynamically check for the NAP feature as it * can be cleared by CPU init after the fixups are done */ @@ -59,16 +52,11 @@ lwz r4,cur_cpu_spec@l(r4) lwz r4,CPU_SPEC_FEATURES(r4) andi. r0,r4,CPU_FTR_CAN_NAP - beq 1f + beqlr /* Now check if user or arch enabled NAP mode */ lis r4,powersave_nap@ha lwz r4,powersave_nap@l(r4) cmpi 0,r4,0 - beq 1f - lis r3,HID0_NAP@h -1: -END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) - cmpi 0,r3,0 beqlr /* Clear MSR:EE */ @@ -85,18 +73,6 @@ blr 1: /* Go to NAP now */ - mfspr r4,SPRN_HID0 - lis r5,(HID0_NAP|HID0_SLEEP)@h - andc r4,r4,r5 - or r4,r4,r3 - oris r4,r4,HID0_DPM@h /* that should be done once for all */ - mtspr SPRN_HID0,r4 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 BEGIN_FTR_SECTION DSSALL sync --- diff/arch/ppc/kernel/misc.S 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ppc/kernel/misc.S 2004-02-09 10:39:51.000000000 +0000 @@ -201,7 +201,7 @@ mr r4,r24 bctr -#ifdef CONFIG_CPU_FREQ_PMAC +#if defined(CONFIG_CPU_FREQ_PMAC) && defined(CONFIG_6xx) /* This gets called by via-pmu.c to switch the PLL selection * on 750fx CPU. This function should really be moved to some @@ -253,7 +253,7 @@ mtmsr r7 blr -#endif /* CONFIG_CPU_FREQ_PMAC */ +#endif /* CONFIG_CPU_FREQ_PMAC && CONFIG_6xx */ /* void local_save_flags_ptr(unsigned long *flags) */ _GLOBAL(local_save_flags_ptr) --- diff/arch/ppc/kernel/pci.c 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/ppc/kernel/pci.c 2004-02-09 10:39:51.000000000 +0000 @@ -46,7 +46,9 @@ static void fixup_rev1_53c810(struct pci_dev* dev); static void fixup_cpc710_pci64(struct pci_dev* dev); #ifdef CONFIG_PPC_PMAC -static void pcibios_fixup_cardbus(struct pci_dev* dev); +extern void pmac_pci_fixup_cardbus(struct pci_dev* dev); +extern void pmac_pci_fixup_pciata(struct pci_dev* dev); +extern void pmac_pci_fixup_k2_sata(struct pci_dev* dev); #endif #ifdef CONFIG_PPC_OF static u8* pci_to_OF_bus_map; @@ -69,7 +71,9 @@ { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources }, #ifdef CONFIG_PPC_PMAC /* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */ - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_ANY_ID, pcibios_fixup_cardbus }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_ANY_ID, pmac_pci_fixup_cardbus }, + { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, 0x0240, pmac_pci_fixup_k2_sata }, #endif /* CONFIG_PPC_PMAC */ { 0 } }; @@ -155,42 +159,6 @@ ppc_md.pcibios_fixup_resources(dev); } -#ifdef CONFIG_PPC_PMAC -static void -pcibios_fixup_cardbus(struct pci_dev* dev) -{ - if (_machine != _MACH_Pmac) - return; - /* - * Fix the interrupt routing on the various cardbus bridges - * used on powerbooks - */ - if (dev->vendor != PCI_VENDOR_ID_TI) - return; - if (dev->device == PCI_DEVICE_ID_TI_1130 || - dev->device == PCI_DEVICE_ID_TI_1131) { - u8 val; - /* Enable PCI interrupt */ - if (pci_read_config_byte(dev, 0x91, &val) == 0) - pci_write_config_byte(dev, 0x91, val | 0x30); - /* Disable ISA interrupt mode */ - if (pci_read_config_byte(dev, 0x92, &val) == 0) - pci_write_config_byte(dev, 0x92, val & ~0x06); - } - if (dev->device == PCI_DEVICE_ID_TI_1210 || - dev->device == PCI_DEVICE_ID_TI_1211 || - dev->device == PCI_DEVICE_ID_TI_1410) { - u8 val; - /* 0x8c == TI122X_IRQMUX, 2 says to route the INTA - signal out the MFUNC0 pin */ - if (pci_read_config_byte(dev, 0x8c, &val) == 0) - pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2); - /* Disable ISA interrupt mode */ - if (pci_read_config_byte(dev, 0x92, &val) == 0) - pci_write_config_byte(dev, 0x92, val & ~0x06); - } -} -#endif /* CONFIG_PPC_PMAC */ void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, @@ -832,6 +800,17 @@ return NULL; /* Fixup bus number according to what OF think it is. */ +#ifdef CONFIG_PPC_PMAC + /* The G5 need a special case here. Basically, we don't remap all + * busses on it so we don't create the pci-OF-map. However, we do + * remap the AGP bus and so have to deal with it. A future better + * fix has to be done by making the remapping per-host and always + * filling the pci_to_OF map. --BenH + */ + if (_machine == _MACH_Pmac && busnr >= 0xf0) + busnr -= 0xf0; + else +#endif if (pci_to_OF_bus_map) busnr = pci_to_OF_bus_map[busnr]; if (busnr == 0xff) @@ -922,9 +901,10 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose, struct device_node *dev, int primary) { - unsigned int *ranges, *prev; + static unsigned int static_lc_ranges[1024] __initdata; + unsigned int *dt_ranges, *lc_ranges, *ranges, *prev; unsigned int size; - int rlen = 0; + int rlen = 0, orig_rlen; int memno = 0; struct resource *res; int np, na = prom_n_addr_cells(dev); @@ -934,7 +914,22 @@ * that can have more than 3 ranges, fortunately using contiguous * addresses -- BenH */ - ranges = (unsigned int *) get_property(dev, "ranges", &rlen); + dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen); + if (!dt_ranges) + return; + /* Sanity check, though hopefully that never happens */ + if (rlen > 1024) { + printk(KERN_WARNING "OF ranges property too large !\n"); + rlen = 1024; + } + lc_ranges = static_lc_ranges; + memcpy(lc_ranges, dt_ranges, rlen); + orig_rlen = rlen; + + /* Let's work on a copy of the "ranges" property instead of damaging + * the device-tree image in memory + */ + ranges = lc_ranges; prev = NULL; while ((rlen -= np * sizeof(unsigned int)) >= 0) { if (prev) { @@ -959,10 +954,9 @@ * (size depending on dev->n_addr_cells) * cells 4+5 or 5+6: the size of the range */ - rlen = 0; - hose->io_base_phys = 0; - ranges = (unsigned int *) get_property(dev, "ranges", &rlen); - while ((rlen -= np * sizeof(unsigned int)) >= 0) { + ranges = lc_ranges; + rlen = orig_rlen; + while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) { res = NULL; size = ranges[na+4]; switch (ranges[0] >> 24) { @@ -1059,7 +1053,7 @@ res = *(bus->resource[0]); - DBG("Remapping Bus %d, bridge: %s\n", bus->number, bridge->name); + DBG("Remapping Bus %d, bridge: %s\n", bus->number, bridge->slot_name); res.start -= ((unsigned long) hose->io_base_virt - isa_io_base); res.end -= ((unsigned long) hose->io_base_virt - isa_io_base); DBG(" IO window: %08lx-%08lx\n", res.start, res.end); @@ -1662,12 +1656,23 @@ * Note that the returned IO or memory base is a physical address */ -long -sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) +long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) { - struct pci_controller* hose = pci_bus_to_hose(bus); + struct pci_controller* hose; long result = -EOPNOTSUPP; + /* Argh ! Please forgive me for that hack, but that's the + * simplest way to get existing XFree to not lockup on some + * G5 machines... So when something asks for bus 0 io base + * (bus 0 is HT root), we return the AGP one instead. + */ +#ifdef CONFIG_PPC_PMAC + if (_machine == _MACH_Pmac && machine_is_compatible("MacRISC4")) + if (bus == 0) + bus = 0xf0; +#endif /* CONFIG_PPC_PMAC */ + + hose = pci_bus_to_hose(bus); if (!hose) return -ENODEV; --- diff/arch/ppc/kernel/ppc_ksyms.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ppc/kernel/ppc_ksyms.c 2004-02-09 10:39:51.000000000 +0000 @@ -75,6 +75,7 @@ extern unsigned long mm_ptov (unsigned long paddr); EXPORT_SYMBOL(clear_page); +EXPORT_SYMBOL(clear_user_page); EXPORT_SYMBOL(do_signal); EXPORT_SYMBOL(do_syscall_trace); EXPORT_SYMBOL(transfer_to_handler); @@ -236,12 +237,6 @@ EXPORT_SYMBOL(cuda_request); EXPORT_SYMBOL(cuda_poll); #endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_PMAC_BACKLIGHT -EXPORT_SYMBOL(get_backlight_level); -EXPORT_SYMBOL(set_backlight_level); -EXPORT_SYMBOL(set_backlight_enable); -EXPORT_SYMBOL(register_backlight_controller); -#endif /* CONFIG_PMAC_BACKLIGHT */ #ifdef CONFIG_PPC_MULTIPLATFORM EXPORT_SYMBOL(_machine); #endif @@ -282,14 +277,6 @@ #ifdef CONFIG_VT EXPORT_SYMBOL(kd_mksound); #endif -#ifdef CONFIG_NVRAM -EXPORT_SYMBOL(nvram_read_byte); -EXPORT_SYMBOL(nvram_write_byte); -#ifdef CONFIG_PPC_PMAC -EXPORT_SYMBOL(pmac_xpram_read); -EXPORT_SYMBOL(pmac_xpram_write); -#endif -#endif /* CONFIG_NVRAM */ EXPORT_SYMBOL(to_tm); EXPORT_SYMBOL(pm_power_off); --- diff/arch/ppc/kernel/setup.c 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ppc/kernel/setup.c 2004-02-09 10:39:51.000000000 +0000 @@ -35,6 +35,7 @@ #include #include #include +#include #include #if defined CONFIG_KGDB @@ -48,11 +49,6 @@ extern void do_cpu_ftr_fixups(unsigned long offset); extern void reloc_got2(unsigned long offset); - -#ifdef CONFIG_KGDB -extern void kgdb_map_scc(void); -#endif - extern void ppc6xx_idle(void); extern void power4_idle(void); @@ -116,6 +112,9 @@ void machine_restart(char *cmd) { +#ifdef CONFIG_NVRAM + nvram_sync(); +#endif ppc_md.restart(cmd); } @@ -123,6 +122,9 @@ void machine_power_off(void) { +#ifdef CONFIG_NVRAM + nvram_sync(); +#endif ppc_md.power_off(); } @@ -130,6 +132,9 @@ void machine_halt(void) { +#ifdef CONFIG_NVRAM + nvram_sync(); +#endif ppc_md.halt(); } @@ -563,24 +568,30 @@ __setup("l2cr=", ppc_setup_l2cr); #ifdef CONFIG_NVRAM -/* Generic nvram hooks we now look into ppc_md.nvram_read_val - * on pmac too ;) - * //XX Those 2 could be moved to headers - */ -unsigned char -nvram_read_byte(int addr) + +/* Generic nvram hooks used by drivers/char/gen_nvram.c */ +unsigned char nvram_read_byte(int addr) { if (ppc_md.nvram_read_val) return ppc_md.nvram_read_val(addr); return 0xff; } +EXPORT_SYMBOL(nvram_read_byte); -void -nvram_write_byte(unsigned char val, int addr) +void nvram_write_byte(unsigned char val, int addr) { if (ppc_md.nvram_write_val) - ppc_md.nvram_write_val(val, addr); + ppc_md.nvram_write_val(addr, val); } +EXPORT_SYMBOL(nvram_write_byte); + +void nvram_sync(void) +{ + if (ppc_md.nvram_sync) + ppc_md.nvram_sync(); +} +EXPORT_SYMBOL(nvram_sync); + #endif /* CONFIG_NVRAM */ static struct cpu cpu_devices[NR_CPUS]; @@ -632,7 +643,8 @@ if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab); #if defined(CONFIG_KGDB) - kgdb_map_scc(); + if (ppc_md.kgdb_map_scc) + ppc_md.kgdb_map_scc(); set_debug_traps(); if (strstr(cmd_line, "gdb")) { if (ppc_md.progress) --- diff/arch/ppc/kernel/smp.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/ppc/kernel/smp.c 2004-02-09 10:39:51.000000000 +0000 @@ -61,10 +61,6 @@ /* all cpu mappings are 1-1 -- Cort */ volatile unsigned long cpu_callin_map[NR_CPUS]; -#define TB_SYNC_PASSES 4 -volatile unsigned long __initdata tb_sync_flag = 0; -volatile unsigned long __initdata tb_offset = 0; - int start_secondary(void *); extern int cpu_idle(void *unused); void smp_call_function_interrupt(void); @@ -83,11 +79,14 @@ #define PPC_MSG_INVALIDATE_TLB 2 #define PPC_MSG_XMON_BREAK 3 -#define smp_message_pass(t,m,d,w) \ - do { if (smp_ops) \ - atomic_inc(&ipi_sent); \ - smp_ops->message_pass((t),(m),(d),(w)); \ - } while(0) +static inline void +smp_message_pass(int target, int msg, unsigned long data, int wait) +{ + if (smp_ops){ + atomic_inc(&ipi_sent); + smp_ops->message_pass(target,msg,data,wait); + } +} /* * Common functions @@ -291,41 +290,6 @@ atomic_inc(&call_data->finished); } -/* FIXME: Do this properly for all archs --RR */ -static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED; -static unsigned int timebase_upper = 0, timebase_lower = 0; - -void __devinit -smp_generic_give_timebase(void) -{ - spin_lock(&timebase_lock); - do { - timebase_upper = get_tbu(); - timebase_lower = get_tbl(); - } while (timebase_upper != get_tbu()); - spin_unlock(&timebase_lock); - - while (timebase_upper || timebase_lower) - rmb(); -} - -void __devinit -smp_generic_take_timebase(void) -{ - int done = 0; - - while (!done) { - spin_lock(&timebase_lock); - if (timebase_upper || timebase_lower) { - set_tb(timebase_upper, timebase_lower); - timebase_upper = 0; - timebase_lower = 0; - done = 1; - } - spin_unlock(&timebase_lock); - } -} - static void __devinit smp_store_cpu_info(int id) { struct cpuinfo_PPC *c = &cpu_data[id]; --- diff/arch/ppc/mm/hashtable.S 2003-10-27 09:20:37.000000000 +0000 +++ source/arch/ppc/mm/hashtable.S 2004-02-09 10:39:51.000000000 +0000 @@ -37,6 +37,32 @@ #endif /* CONFIG_SMP */ /* + * Sync CPUs with hash_page taking & releasing the hash + * table lock + */ +#ifdef CONFIG_SMP + .text +_GLOBAL(hash_page_sync) + lis r8,mmu_hash_lock@h + ori r8,r8,mmu_hash_lock@l + lis r0,0x0fff + b 10f +11: lwz r6,0(r8) + cmpwi 0,r6,0 + bne 11b +10: lwarx r6,0,r8 + cmpwi 0,r6,0 + bne- 11b + stwcx. r0,0,r8 + bne- 10b + isync + eieio + li r0,0 + stw r0,0(r8) + blr +#endif + +/* * 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. @@ -417,21 +443,6 @@ 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 --- diff/arch/ppc/mm/init.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/ppc/mm/init.c 2004-02-09 10:39:51.000000000 +0000 @@ -291,6 +291,8 @@ ppc_md.progress("MMU:exit", 0x211); #ifdef CONFIG_BOOTX_TEXT + /* By default, we are no longer mapped */ + boot_text_mapped = 0; /* Must be done last, or ppc_md.progress will die. */ map_boot_text(); #endif --- diff/arch/ppc/mm/pgtable.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/ppc/mm/pgtable.c 2004-02-09 10:39:51.000000000 +0000 @@ -44,6 +44,10 @@ extern char etext[], _stext[]; +#ifdef CONFIG_SMP +extern void hash_page_sync(void); +#endif + #ifdef HAVE_BATS extern unsigned long v_mapped_by_bats(unsigned long va); extern unsigned long p_mapped_by_bats(unsigned long pa); @@ -109,11 +113,17 @@ void pte_free_kernel(pte_t *pte) { +#ifdef CONFIG_SMP + hash_page_sync(); +#endif free_page((unsigned long)pte); } void pte_free(struct page *pte) { +#ifdef CONFIG_SMP + hash_page_sync(); +#endif __free_page(pte); } --- diff/arch/ppc/mm/ppc_mmu.c 2003-10-27 09:20:37.000000000 +0000 +++ source/arch/ppc/mm/ppc_mmu.c 2004-02-09 10:39:51.000000000 +0000 @@ -83,6 +83,9 @@ unsigned long __init mmu_mapin_ram(void) { +#ifdef CONFIG_POWER4 + return 0; +#else unsigned long tot, bl, done; unsigned long max_size = (256<<20); unsigned long align; @@ -119,6 +122,7 @@ } return done; +#endif } /* @@ -244,9 +248,10 @@ Hash = mem_pieces_find(Hash_size, Hash_size); cacheable_memzero(Hash, Hash_size); _SDR1 = __pa(Hash) | SDR1_LOW_BITS; - Hash_end = (PTE *) ((unsigned long)Hash + Hash_size); #endif /* CONFIG_POWER4 */ + Hash_end = (PTE *) ((unsigned long)Hash + Hash_size); + printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n", total_memory >> 20, Hash_size >> 10, Hash); --- diff/arch/ppc/mm/tlb.c 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/ppc/mm/tlb.c 2004-02-09 10:39:51.000000000 +0000 @@ -47,6 +47,26 @@ } /* + * Called by ptep_test_and_clear_young() + */ +void flush_hash_one_pte(pte_t *ptep) +{ + struct page *ptepage; + struct mm_struct *mm; + unsigned long ptephys; + unsigned long addr; + + if (Hash == 0) + return; + + ptepage = virt_to_page(ptep); + mm = (struct mm_struct *) ptepage->mapping; + ptephys = __pa(ptep) & PAGE_MASK; + addr = ptepage->index + (((unsigned long)ptep & ~PAGE_MASK) << 9); + flush_hash_pages(mm->context, addr, ptephys, 1); +} + +/* * Called at the end of a mmu_gather operation to make sure the * TLB flush is completely done. */ --- diff/arch/ppc/platforms/Makefile 2003-07-11 09:39:50.000000000 +0100 +++ source/arch/ppc/platforms/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -17,7 +17,8 @@ obj-$(CONFIG_PCI) += apus_pci.o endif obj-$(CONFIG_PPC_PMAC) += pmac_pic.o pmac_setup.o pmac_time.o \ - pmac_feature.o pmac_pci.o pmac_sleep.o + pmac_feature.o pmac_pci.o pmac_sleep.o \ + pmac_low_i2c.o obj-$(CONFIG_PPC_CHRP) += chrp_setup.o chrp_time.o chrp_pci.o obj-$(CONFIG_PPC_PREP) += prep_pci.o prep_time.o prep_setup.o ifeq ($(CONFIG_PPC_PMAC),y) --- diff/arch/ppc/platforms/mcpn765_setup.c 2003-09-17 12:28:02.000000000 +0100 +++ source/arch/ppc/platforms/mcpn765_setup.c 2004-02-09 10:39:51.000000000 +0000 @@ -50,6 +50,7 @@ #include #include #include +#include #include "mcpn765.h" #include "mcpn765_serial.h" @@ -78,9 +79,6 @@ extern u_int openpic_irq(void); extern char cmd_line[]; -extern void gen550_progress(char *, unsigned short); -extern void gen550_init(int, struct uart_port *); - int use_of_interrupt_tree = 0; static void mcpn765_halt(void); @@ -472,6 +470,9 @@ #if defined(CONFIG_SERIAL_8250) && \ (defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)) mcpn765_early_serial_map(); +#ifdef CONFIG_KGDB + ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; +#endif #ifdef CONFIG_SERIAL_TEXT_DEBUG ppc_md.progress = gen550_progress; #endif --- diff/arch/ppc/platforms/pmac_backlight.c 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/ppc/platforms/pmac_backlight.c 2004-02-09 10:39:51.000000000 +0000 @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -37,6 +38,10 @@ char *prop; int valid = 0; + /* There's already a matching controller, bail out */ + if (backlighter != NULL) + return; + bk_node = find_devices("backlight"); #ifdef CONFIG_ADB_PMU @@ -84,6 +89,7 @@ printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n", type, backlight_level); } +EXPORT_SYMBOL(register_backlight_controller); void __pmac unregister_backlight_controller(struct backlight_controller *ctrler, void *data) @@ -92,6 +98,7 @@ if (ctrler == backlighter && data == backlighter_data) backlighter = NULL; } +EXPORT_SYMBOL(unregister_backlight_controller); int __pmac set_backlight_enable(int enable) @@ -105,6 +112,7 @@ backlight_enabled = enable; return rc; } +EXPORT_SYMBOL(set_backlight_enable); int __pmac get_backlight_enable(void) @@ -113,6 +121,7 @@ return -ENODEV; return backlight_enabled; } +EXPORT_SYMBOL(get_backlight_enable); int __pmac set_backlight_level(int level) @@ -137,6 +146,7 @@ } return rc; } +EXPORT_SYMBOL(set_backlight_level); int __pmac get_backlight_level(void) @@ -145,3 +155,4 @@ return -ENODEV; return backlight_level; } +EXPORT_SYMBOL(get_backlight_level); --- diff/arch/ppc/platforms/pmac_cpufreq.c 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/ppc/platforms/pmac_cpufreq.c 2004-02-09 10:39:51.000000000 +0000 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,14 @@ */ #undef DEBUG_FREQ +/* + * There is a problem with the core cpufreq code on SMP kernels, + * it won't recalculate the Bogomips properly + */ +#ifdef CONFIG_SMP +#warning "WARNING, CPUFREQ not recommended on SMP kernels" +#endif + extern void low_choose_750fx_pll(int pll); extern void low_sleep_handler(void); extern void openpic_suspend(struct sys_device *sysdev, u32 state); @@ -48,7 +57,14 @@ static unsigned int low_freq; static unsigned int hi_freq; static unsigned int cur_freq; + +/* Clean that up some day ... use a func ptr or at least an enum... */ static int cpufreq_uses_pmu; +static int cpufreq_uses_gpios; + +static u32 voltage_gpio; +static u32 frequency_gpio; +static u32 slew_done_gpio; #define PMAC_CPU_LOW_SPEED 1 #define PMAC_CPU_HIGH_SPEED 0 @@ -65,8 +81,7 @@ {0, CPUFREQ_TABLE_END}, }; -static inline void -wakeup_decrementer(void) +static inline void wakeup_decrementer(void) { set_dec(tb_ticks_per_jiffy); /* No currently-supported powerbook has a 601, @@ -76,8 +91,7 @@ } #ifdef DEBUG_FREQ -static inline void -debug_calc_bogomips(void) +static inline void debug_calc_bogomips(void) { /* This will cause a recalc of bogomips and display the * result. We backup/restore the value to avoid affecting the @@ -89,17 +103,18 @@ calibrate_delay(); loops_per_jiffy = save_lpj; } -#endif +#endif /* DEBUG_FREQ */ /* Switch CPU speed under 750FX CPU control */ -static int __pmac -cpu_750fx_cpu_speed(int low_speed) +static int __pmac cpu_750fx_cpu_speed(int low_speed) { #ifdef DEBUG_FREQ printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); #endif +#ifdef CONFIG_6xx low_choose_750fx_pll(low_speed); +#endif #ifdef DEBUG_FREQ printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); debug_calc_bogomips(); @@ -108,15 +123,54 @@ return 0; } +/* Switch CPU speed using slewing GPIOs + */ +static int __pmac gpios_set_cpu_speed(unsigned int low_speed) +{ + int gpio; + + /* If ramping up, set voltage first */ + if (low_speed == 0) { + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05); + /* Delay is way too big but it's ok, we schedule */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/100); + } + + /* Set frequency */ + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio, low_speed ? 0x04 : 0x05); + udelay(200); + do { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + gpio = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, slew_done_gpio, 0); + } while((gpio & 0x02) == 0); + + /* If ramping down, set voltage last */ + if (low_speed == 1) { + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04); + /* Delay is way too big but it's ok, we schedule */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/100); + } + +#ifdef DEBUG_FREQ + debug_calc_bogomips(); +#endif + + return 0; +} + /* Switch CPU speed under PMU control */ -static int __pmac -pmu_set_cpu_speed(unsigned int low_speed) +static int __pmac pmu_set_cpu_speed(unsigned int low_speed) { struct adb_request req; unsigned long save_l2cr; unsigned long save_l3cr; + preempt_disable(); + #ifdef DEBUG_FREQ printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); #endif @@ -197,11 +251,12 @@ debug_calc_bogomips(); #endif + preempt_enable(); + return 0; } -static int __pmac -do_set_cpu_speed(int speed_mode) +static int __pmac do_set_cpu_speed(int speed_mode) { struct cpufreq_freqs freqs; int rc; @@ -216,6 +271,8 @@ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); if (cpufreq_uses_pmu) rc = pmu_set_cpu_speed(speed_mode); + else if (cpufreq_uses_gpios) + rc = gpios_set_cpu_speed(speed_mode); else rc = cpu_750fx_cpu_speed(speed_mode); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); @@ -224,16 +281,14 @@ return rc; } -static int __pmac -pmac_cpufreq_verify(struct cpufreq_policy *policy) +static int __pmac pmac_cpufreq_verify(struct cpufreq_policy *policy) { return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs); } -static int __pmac -pmac_cpufreq_target( struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int __pmac pmac_cpufreq_target( struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) { unsigned int newstate = 0; @@ -244,15 +299,13 @@ return do_set_cpu_speed(newstate); } -unsigned int __pmac -pmac_get_one_cpufreq(int i) +unsigned int __pmac pmac_get_one_cpufreq(int i) { /* Supports only one CPU for now */ return (i == 0) ? cur_freq : 0; } -static int __pmac -pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) +static int __pmac pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) { if (policy->cpu != 0) return -ENODEV; @@ -264,6 +317,18 @@ return cpufreq_frequency_table_cpuinfo(policy, &pmac_cpu_freqs[0]); } +static u32 __pmac read_gpio(struct device_node *np) +{ + u32 *reg = (u32 *)get_property(np, "reg", NULL); + + if (reg == NULL) + return 0; + /* That works for all keylargos but shall be fixed properly + * some day... + */ + return 0x50 + (*reg); +} + static struct cpufreq_driver pmac_cpufreq_driver = { .verify = pmac_cpufreq_verify, .target = pmac_cpufreq_target, @@ -272,15 +337,17 @@ .owner = THIS_MODULE, }; + /* Currently, we support the following machines: * + * - Titanium PowerBook 1Ghz (PMU based, 667Mhz & 1Ghz) * - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz) * - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz) * - iBook2 500 (PMU based, 400Mhz & 500Mhz) * - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage) + * - Recent MacRISC3 machines */ -static int __init -pmac_cpufreq_setup(void) +static int __init pmac_cpufreq_setup(void) { struct device_node *cpunode; u32 *value; @@ -304,6 +371,74 @@ if (machine_is_compatible("PowerBook3,4") || machine_is_compatible("PowerBook3,5") || machine_is_compatible("MacRISC3")) { + struct device_node *volt_gpio_np = of_find_node_by_name(NULL, "voltage-gpio"); + struct device_node *freq_gpio_np = of_find_node_by_name(NULL, "frequency-gpio"); + struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL, "slewing-done"); + + /* + * Check to see if it's GPIO driven or PMU only + * + * The way we extract the GPIO address is slightly hackish, but it + * works well enough for now. We need to abstract the whole GPIO + * stuff sooner or later anyway + */ + + if (volt_gpio_np) + voltage_gpio = read_gpio(volt_gpio_np); + if (freq_gpio_np) + frequency_gpio = read_gpio(freq_gpio_np); + if (slew_done_gpio_np) + slew_done_gpio = read_gpio(slew_done_gpio_np); + + /* If we use the frequency GPIOs, calculate the min/max speeds based + * on the bus frequencies + */ + if (frequency_gpio && slew_done_gpio) { + int lenp, rc; + u32 *freqs, *ratio; + + freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp); + lenp /= sizeof(u32); + if (freqs == NULL || lenp != 2) { + printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n"); + goto out; + } + ratio = (u32 *)get_property(cpunode, "processor-to-bus-ratio*2", NULL); + if (ratio == NULL) { + printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n"); + goto out; + } + + /* Get the min/max bus frequencies */ + low_freq = min(freqs[0], freqs[1]); + hi_freq = max(freqs[0], freqs[1]); + + /* Grrrr.. It _seems_ that the device-tree is lying on the low bus + * frequency, it claims it to be around 84Mhz on some models while + * it appears to be approx. 101Mhz on all. Let's hack around here... + * fortunately, we don't need to be too precise + */ + if (low_freq < 98000000) + low_freq = 101000000; + + /* Convert those to CPU core clocks */ + low_freq = (low_freq * (*ratio)) / 2000; + hi_freq = (hi_freq * (*ratio)) / 2000; + + /* Now we get the frequencies, we read the GPIO to see what is out current + * speed + */ + rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0); + cur_freq = (rc & 0x01) ? hi_freq : low_freq; + + has_freq_ctl = 1; + cpufreq_uses_gpios = 1; + goto out; + } + + /* If we use the PMU, look for the min & max frequencies in the + * device-tree + */ value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL); if (!value) goto out; @@ -359,6 +494,11 @@ pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq; pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq; + printk(KERN_INFO "Registering PowerMac CPU frequency driver\n"); + printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz, switch method: %s\n", + low_freq/1000, hi_freq/1000, cur_freq/1000, + cpufreq_uses_pmu ? "PMU" : (cpufreq_uses_gpios ? "GPIOs" : "CPU")); + return cpufreq_register_driver(&pmac_cpufreq_driver); } --- diff/arch/ppc/platforms/pmac_feature.c 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/ppc/platforms/pmac_feature.c 2004-02-09 10:39:51.000000000 +0000 @@ -41,6 +41,7 @@ #include #include #include +#include #undef DEBUG_FEATURE @@ -50,9 +51,13 @@ #define DBG(fmt,...) #endif -/* Exported from arch/ppc/kernel/idle.c */ +#ifdef CONFIG_6xx extern int powersave_lowspeed; +#endif + extern int powersave_nap; +extern struct pci_dev *k2_skiplist[2]; + /* * We use a single global lock to protect accesses. Each driver has @@ -95,7 +100,8 @@ "Paddington", "Keylargo", "Pangea", - "Intrepid" + "Intrepid", + "K2" }; @@ -113,14 +119,15 @@ static struct device_node* uninorth_node __pmacdata; static u32* uninorth_base __pmacdata; static u32 uninorth_rev __pmacdata; - +static int uninorth_u3 __pmacdata; +static void *u3_ht; /* * For each motherboard family, we have a table of functions pointers * that handle the various features. */ -typedef int (*feature_call)(struct device_node* node, int param, int value); +typedef long (*feature_call)(struct device_node* node, long param, long value); struct feature_table_entry { unsigned int selector; @@ -161,8 +168,10 @@ return 0; } -static int __pmac -ohare_htw_scc_enable(struct device_node* node, int param, int value) +#ifndef CONFIG_POWER4 + +static long __pmac +ohare_htw_scc_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; unsigned long chan_mask; @@ -254,22 +263,22 @@ return 0; } -static int __pmac -ohare_floppy_enable(struct device_node* node, int param, int value) +static long __pmac +ohare_floppy_enable(struct device_node* node, long param, long value) { return simple_feature_tweak(node, macio_ohare, OHARE_FCR, OH_FLOPPY_ENABLE, value); } -static int __pmac -ohare_mesh_enable(struct device_node* node, int param, int value) +static long __pmac +ohare_mesh_enable(struct device_node* node, long param, long value) { return simple_feature_tweak(node, macio_ohare, OHARE_FCR, OH_MESH_ENABLE, value); } -static int __pmac -ohare_ide_enable(struct device_node* node, int param, int value) +static long __pmac +ohare_ide_enable(struct device_node* node, long param, long value) { switch(param) { case 0: @@ -289,8 +298,8 @@ } } -static int __pmac -ohare_ide_reset(struct device_node* node, int param, int value) +static long __pmac +ohare_ide_reset(struct device_node* node, long param, long value) { switch(param) { case 0: @@ -304,8 +313,8 @@ } } -static int __pmac -ohare_sleep_state(struct device_node* node, int param, int value) +static long __pmac +ohare_sleep_state(struct device_node* node, long param, long value) { struct macio_chip* macio = &macio_chips[0]; @@ -320,8 +329,8 @@ return 0; } -static int __pmac -heathrow_modem_enable(struct device_node* node, int param, int value) +static long __pmac +heathrow_modem_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; u8 gpio; @@ -364,8 +373,8 @@ return 0; } -static int __pmac -heathrow_floppy_enable(struct device_node* node, int param, int value) +static long __pmac +heathrow_floppy_enable(struct device_node* node, long param, long value) { return simple_feature_tweak(node, macio_unknown, HEATHROW_FCR, @@ -373,8 +382,8 @@ value); } -static int __pmac -heathrow_mesh_enable(struct device_node* node, int param, int value) +static long __pmac +heathrow_mesh_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; unsigned long flags; @@ -390,22 +399,11 @@ MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE); (void)MACIO_IN32(HEATHROW_FCR); udelay(10); - /* Set/Clear termination power (todo: test ! the bit value - * used by Darwin doesn't seem to match what we used so - * far. If you experience problems, turn #if 1 into #if 0 - * and tell me about it --BenH. - */ -#if 1 + /* Set/Clear termination power */ if (value) - MACIO_BIC(HEATHROW_MBCR, 0x00000004); + MACIO_BIC(HEATHROW_MBCR, 0x04000000); else - MACIO_BIS(HEATHROW_MBCR, 0x00000004); -#else - if (value) - MACIO_BIC(HEATHROW_MBCR, 0x00040000); - else - MACIO_BIS(HEATHROW_MBCR, 0x00040000); -#endif + MACIO_BIS(HEATHROW_MBCR, 0x04000000); (void)MACIO_IN32(HEATHROW_MBCR); udelay(10); UNLOCK(flags); @@ -413,8 +411,8 @@ return 0; } -static int __pmac -heathrow_ide_enable(struct device_node* node, int param, int value) +static long __pmac +heathrow_ide_enable(struct device_node* node, long param, long value) { switch(param) { case 0: @@ -428,8 +426,8 @@ } } -static int __pmac -heathrow_ide_reset(struct device_node* node, int param, int value) +static long __pmac +heathrow_ide_reset(struct device_node* node, long param, long value) { switch(param) { case 0: @@ -443,8 +441,8 @@ } } -static int __pmac -heathrow_bmac_enable(struct device_node* node, int param, int value) +static long __pmac +heathrow_bmac_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; unsigned long flags; @@ -472,8 +470,8 @@ return 0; } -static int __pmac -heathrow_sound_enable(struct device_node* node, int param, int value) +static long __pmac +heathrow_sound_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; unsigned long flags; @@ -608,8 +606,8 @@ } } -static int __pmac -heathrow_sleep_state(struct device_node* node, int param, int value) +static long __pmac +heathrow_sleep_state(struct device_node* node, long param, long value) { if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0) return -EPERM; @@ -625,8 +623,8 @@ return 0; } -static int __pmac -core99_scc_enable(struct device_node* node, int param, int value) +static long __pmac +core99_scc_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; unsigned long flags; @@ -726,8 +724,8 @@ return 0; } -static int __pmac -core99_modem_enable(struct device_node* node, int param, int value) +static long __pmac +core99_modem_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; u8 gpio; @@ -778,8 +776,8 @@ return 0; } -static int __pmac -pangea_modem_enable(struct device_node* node, int param, int value) +static long __pmac +pangea_modem_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; u8 gpio; @@ -833,8 +831,8 @@ return 0; } -static int __pmac -core99_ata100_enable(struct device_node* node, int value) +static long __pmac +core99_ata100_enable(struct device_node* node, long value) { unsigned long flags; struct pci_dev *pdev = NULL; @@ -863,8 +861,8 @@ return 0; } -static int __pmac -core99_ide_enable(struct device_node* node, int param, int value) +static long __pmac +core99_ide_enable(struct device_node* node, long param, long value) { /* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2 * based ata-100 @@ -886,8 +884,8 @@ } } -static int __pmac -core99_ide_reset(struct device_node* node, int param, int value) +static long __pmac +core99_ide_reset(struct device_node* node, long param, long value) { switch(param) { case 0: @@ -904,8 +902,8 @@ } } -static int __pmac -core99_gmac_enable(struct device_node* node, int param, int value) +static long __pmac +core99_gmac_enable(struct device_node* node, long param, long value) { unsigned long flags; @@ -921,8 +919,8 @@ return 0; } -static int __pmac -core99_gmac_phy_reset(struct device_node* node, int param, int value) +static long __pmac +core99_gmac_phy_reset(struct device_node* node, long param, long value) { unsigned long flags; struct macio_chip* macio; @@ -938,16 +936,16 @@ UNLOCK(flags); mdelay(10); LOCK(flags); - MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE - | KEYLARGO_GPIO_OUTOUT_DATA); + MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, /*KEYLARGO_GPIO_OUTPUT_ENABLE | */ + KEYLARGO_GPIO_OUTOUT_DATA); UNLOCK(flags); mdelay(10); return 0; } -static int __pmac -core99_sound_chip_enable(struct device_node* node, int param, int value) +static long __pmac +core99_sound_chip_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; unsigned long flags; @@ -976,8 +974,8 @@ return 0; } -static int __pmac -core99_airport_enable(struct device_node* node, int param, int value) +static long __pmac +core99_airport_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; unsigned long flags; @@ -1063,8 +1061,8 @@ } #ifdef CONFIG_SMP -static int __pmac -core99_reset_cpu(struct device_node* node, int param, int value) +static long __pmac +core99_reset_cpu(struct device_node* node, long param, long value) { unsigned int reset_io = 0; unsigned long flags; @@ -1099,7 +1097,7 @@ MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); (void)MACIO_IN8(reset_io); udelay(1); - MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTOUT_DATA | KEYLARGO_GPIO_OUTPUT_ENABLE); + MACIO_OUT8(reset_io, 0); (void)MACIO_IN8(reset_io); UNLOCK(flags); @@ -1107,8 +1105,8 @@ } #endif /* CONFIG_SMP */ -static int __pmac -core99_usb_enable(struct device_node* node, int param, int value) +static long __pmac +core99_usb_enable(struct device_node* node, long param, long value) { struct macio_chip* macio; unsigned long flags; @@ -1121,9 +1119,6 @@ macio->type != macio_intrepid) return -ENODEV; - /* XXX Fix handling of 3rd USB controller in Intrepid, move the - * port connect stuff (KL4_*) to the sleep code eventually - */ prop = (char *)get_property(node, "AAPL,clock-id", NULL); if (!prop) return -ENODEV; @@ -1131,6 +1126,8 @@ number = 0; else if (strncmp(prop, "usb1u148", 8) == 0) number = 2; + else if (strncmp(prop, "usb2u248", 8) == 0) + number = 4; else return -ENODEV; @@ -1147,44 +1144,79 @@ mdelay(1); LOCK(flags); MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); - } else { + } else if (number == 2) { MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); UNLOCK(flags); (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); LOCK(flags); MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + } else if (number == 4) { + MACIO_BIC(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1)); + UNLOCK(flags); + (void)MACIO_IN32(KEYLARGO_FCR1); + mdelay(1); + LOCK(flags); + MACIO_BIS(KEYLARGO_FCR0, KL1_USB2_CELL_ENABLE); + } + if (number < 4) { + reg = MACIO_IN32(KEYLARGO_FCR4); + reg &= ~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) | + KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number)); + reg &= ~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) | + KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1)); + MACIO_OUT32(KEYLARGO_FCR4, reg); + (void)MACIO_IN32(KEYLARGO_FCR4); + udelay(10); + } else { + reg = MACIO_IN32(KEYLARGO_FCR3); + reg &= ~(KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) | + KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0)); + reg &= ~(KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) | + KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1)); + MACIO_OUT32(KEYLARGO_FCR3, reg); + (void)MACIO_IN32(KEYLARGO_FCR3); + udelay(10); } - reg = MACIO_IN32(KEYLARGO_FCR4); - reg &= ~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) | - KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number)); - reg &= ~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) | - KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1)); - MACIO_OUT32(KEYLARGO_FCR4, reg); - (void)MACIO_IN32(KEYLARGO_FCR4); - udelay(10); } else { /* Turn OFF */ - reg = MACIO_IN32(KEYLARGO_FCR4); - reg |= KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) | - KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number); - reg |= KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) | - KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1); - MACIO_OUT32(KEYLARGO_FCR4, reg); - (void)MACIO_IN32(KEYLARGO_FCR4); - udelay(1); + if (number < 4) { + reg = MACIO_IN32(KEYLARGO_FCR4); + reg |= KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) | + KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number); + reg |= KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) | + KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1); + MACIO_OUT32(KEYLARGO_FCR4, reg); + (void)MACIO_IN32(KEYLARGO_FCR4); + udelay(1); + } else { + reg = MACIO_IN32(KEYLARGO_FCR3); + reg |= KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) | + KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0); + reg |= KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) | + KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1); + MACIO_OUT32(KEYLARGO_FCR3, reg); + (void)MACIO_IN32(KEYLARGO_FCR3); + udelay(1); + } if (number == 0) { MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); (void)MACIO_IN32(KEYLARGO_FCR0); udelay(1); MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); (void)MACIO_IN32(KEYLARGO_FCR0); - } else { + } else if (number == 2) { MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); (void)MACIO_IN32(KEYLARGO_FCR0); udelay(1); MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); (void)MACIO_IN32(KEYLARGO_FCR0); + } else if (number == 4) { + MACIO_BIC(KEYLARGO_FCR1, KL1_USB2_CELL_ENABLE); + (void)MACIO_IN32(KEYLARGO_FCR1); + udelay(1); + MACIO_BIS(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1)); + (void)MACIO_IN32(KEYLARGO_FCR1); } udelay(1); } @@ -1193,8 +1225,8 @@ return 0; } -static int __pmac -core99_firewire_enable(struct device_node* node, int param, int value) +static long __pmac +core99_firewire_enable(struct device_node* node, long param, long value) { unsigned long flags; struct macio_chip* macio; @@ -1220,8 +1252,8 @@ return 0; } -static int __pmac -core99_firewire_cable_power(struct device_node* node, int param, int value) +static long __pmac +core99_firewire_cable_power(struct device_node* node, long param, long value) { unsigned long flags; struct macio_chip* macio; @@ -1251,8 +1283,10 @@ return 0; } -static int __pmac -core99_read_gpio(struct device_node* node, int param, int value) +#endif /* CONFIG_POWER4 */ + +static long __pmac +core99_read_gpio(struct device_node* node, long param, long value) { struct macio_chip* macio = &macio_chips[0]; @@ -1260,8 +1294,8 @@ } -static int __pmac -core99_write_gpio(struct device_node* node, int param, int value) +static long __pmac +core99_write_gpio(struct device_node* node, long param, long value) { struct macio_chip* macio = &macio_chips[0]; @@ -1269,6 +1303,145 @@ return 0; } +#ifdef CONFIG_POWER4 + +static long __pmac +g5_gmac_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio = &macio_chips[0]; + unsigned long flags; + struct pci_dev *pdev; + u8 pbus, pid; + + /* XXX FIXME: We should fix pci_device_from_OF_node here, and + * get to a real pci_dev or we'll get into trouble with PCI + * domains the day we get overlapping numbers (like if we ever + * decide to show the HT root + */ + if (pci_device_from_OF_node(node, &pbus, &pid) == 0) + pdev = pci_find_slot(pbus, pid); + + LOCK(flags); + if (value) { + MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); + mb(); + k2_skiplist[0] = NULL; + } else { + k2_skiplist[0] = pdev; + mb(); + MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); + } + + UNLOCK(flags); + mdelay(1); + + return 0; +} + +static long __pmac +g5_fw_enable(struct device_node* node, long param, long value) +{ + struct macio_chip* macio = &macio_chips[0]; + unsigned long flags; + struct pci_dev *pdev; + u8 pbus, pid; + + /* XXX FIXME: We should fix pci_device_from_OF_node here, and + * get to a real pci_dev or we'll get into trouble with PCI + * domains the day we get overlapping numbers (like if we ever + * decide to show the HT root + */ + if (pci_device_from_OF_node(node, &pbus, &pid) == 0) + pdev = pci_find_slot(pbus, pid); + + LOCK(flags); + if (value) { + MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); + mb(); + k2_skiplist[1] = NULL; + } else { + k2_skiplist[0] = pdev; + mb(); + MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); + } + + UNLOCK(flags); + mdelay(1); + + return 0; +} + +static long __pmac +g5_mpic_enable(struct device_node* node, long param, long value) +{ + unsigned long flags; + + if (node->parent == NULL || strcmp(node->parent->name, "u3")) + return 0; + + LOCK(flags); + UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE); + UNLOCK(flags); + + return 0; +} + +#ifdef CONFIG_SMP +static long __pmac +g5_reset_cpu(struct device_node* node, long param, long value) +{ + unsigned int reset_io = 0; + unsigned long flags; + struct macio_chip* macio; + struct device_node* np; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo2) + return -ENODEV; + + np = find_path_device("/cpus"); + if (np == NULL) + return -ENODEV; + for (np = np->child; np != NULL; np = np->sibling) { + u32* num = (u32 *)get_property(np, "reg", NULL); + u32* rst = (u32 *)get_property(np, "soft-reset", NULL); + if (num == NULL || rst == NULL) + continue; + if (param == *num) { + reset_io = *rst; + break; + } + } + if (np == NULL || reset_io == 0) + return -ENODEV; + + LOCK(flags); + MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); + (void)MACIO_IN8(reset_io); + udelay(1); + MACIO_OUT8(reset_io, 0); + (void)MACIO_IN8(reset_io); + UNLOCK(flags); + + return 0; +} +#endif /* CONFIG_SMP */ + +/* + * This can be called from pmac_smp so isn't static + * + * This takes the second CPU off the bus on dual CPU machines + * running UP + */ +void __pmac g5_phy_disable_cpu1(void) +{ + UN_OUT(U3_API_PHY_CONFIG_1, 0); +} + +#endif /* CONFIG_POWER4 */ + +#ifndef CONFIG_POWER4 + static void __pmac keylargo_shutdown(struct macio_chip* macio, int sleep_mode) { @@ -1541,8 +1714,8 @@ return 0; } -static int __pmac -core99_sleep_state(struct device_node* node, int param, int value) +static long __pmac +core99_sleep_state(struct device_node* node, long param, long value) { /* Param == 1 means to enter the "fake sleep" mode that is * used for CPU speed switch @@ -1568,8 +1741,10 @@ return 0; } -static int __pmac -generic_get_mb_info(struct device_node* node, int param, int value) +#endif /* CONFIG_POWER4 */ + +static long __pmac +generic_get_mb_info(struct device_node* node, long param, long value) { switch(param) { case PMAC_MB_INFO_MODEL: @@ -1579,9 +1754,9 @@ case PMAC_MB_INFO_NAME: /* hack hack hack... but should work */ *((const char **)value) = pmac_mb.model_name; - break; + return 0; } - return 0; + return -EINVAL; } @@ -1596,6 +1771,8 @@ { 0, NULL } }; +#ifndef CONFIG_POWER4 + /* OHare based motherboards. Currently, we only use these on the * 2400,3400 and 3500 series powerbooks. Some older desktops seem * to have issues with turning on/off those asic cells @@ -1741,10 +1918,29 @@ { 0, NULL } }; +#else /* CONFIG_POWER4 */ + +/* G5 features + */ +static struct feature_table_entry g5_features[] __pmacdata = { + { PMAC_FTR_GMAC_ENABLE, g5_gmac_enable }, + { PMAC_FTR_1394_ENABLE, g5_fw_enable }, + { PMAC_FTR_ENABLE_MPIC, g5_mpic_enable }, +#ifdef CONFIG_SMP + { PMAC_FTR_RESET_CPU, g5_reset_cpu }, +#endif /* CONFIG_SMP */ + { PMAC_FTR_READ_GPIO, core99_read_gpio }, + { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, + { 0, NULL } +}; + +#endif /* CONFIG_POWER4 */ + static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { /* Warning: ordering is important as some models may claim * beeing compatible with several types */ +#ifndef CONFIG_POWER4 { "AAPL,8500", "PowerMac 8500/8600", PMAC_TYPE_PSURGE, NULL, 0 @@ -1753,6 +1949,14 @@ PMAC_TYPE_PSURGE, NULL, 0 }, + { "AAPL,7200", "PowerMac 7200", + PMAC_TYPE_PSURGE, NULL, + 0 + }, + { "AAPL,7300", "PowerMac 7200/7300", + PMAC_TYPE_PSURGE, NULL, + 0 + }, { "AAPL,7500", "PowerMac 7500", PMAC_TYPE_PSURGE, NULL, 0 @@ -1905,20 +2109,43 @@ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, }, + { "PowerBook5,2", "PowerBook G4 15\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook5,3", "PowerBook G4 17\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, { "PowerBook6,1", "PowerBook G4 12\"", PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, }, + { "PowerBook6,2", "PowerBook G4", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, + { "PowerBook6,3", "iBook G4", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, +#else /* CONFIG_POWER4 */ + { "PowerMac7,2", "PowerMac G5", + PMAC_TYPE_POWERMAC_G5, g5_features, + 0, + }, +#endif /* CONFIG_POWER4 */ }; /* * The toplevel feature_call callback */ -int __pmac +long __pmac pmac_do_feature_call(unsigned int selector, ...) { struct device_node* node; - int param, value, i; + long param, value; + int i; feature_call func = NULL; va_list args; @@ -1939,8 +2166,8 @@ va_start(args, selector); node = (struct device_node*)va_arg(args, void*); - param = va_arg(args, int); - value = va_arg(args, int); + param = va_arg(args, long); + value = va_arg(args, long); va_end(args); return func(node, param, value); @@ -1976,6 +2203,7 @@ /* Fallback to selection depending on mac-io chip type */ switch(macio->type) { +#ifndef CONFIG_POWER4 case macio_grand_central: pmac_mb.model_id = PMAC_TYPE_PSURGE; pmac_mb.model_name = "Unknown PowerSurge"; @@ -2009,10 +2237,18 @@ pmac_mb.model_name = "Unknown Intrepid-based"; pmac_mb.features = intrepid_features; break; +#else /* CONFIG_POWER4 */ + case macio_keylargo2: + pmac_mb.model_id = PMAC_TYPE_POWERMAC_G5; + pmac_mb.model_name = "Unknown G5"; + pmac_mb.features = g5_features; + break; +#endif /* CONFIG_POWER4 */ default: return -ENODEV; } found: +#ifndef CONFIG_POWER4 /* Fixup Hooper vs. Comet */ if (pmac_mb.model_id == PMAC_TYPE_HOOPER) { u32* mach_id_ptr = (u32*)ioremap(0xf3000034, 4); @@ -2026,6 +2262,7 @@ pmac_mb.model_id = PMAC_TYPE_COMET; iounmap(mach_id_ptr); } +#endif /* CONFIG_POWER4 */ #ifdef CONFIG_6xx /* Set default value of powersave_nap on machines that support it. @@ -2057,7 +2294,9 @@ */ powersave_lowspeed = 1; #endif /* CONFIG_6xx */ - +#ifdef CONFIG_POWER4 + powersave_nap = 1; +#endif /* Check for "mobile" machine */ if (model && (strncmp(model, "PowerBook", 9) == 0 || strncmp(model, "iBook", 5) == 0)) @@ -2076,18 +2315,26 @@ unsigned long actrl; /* Locate core99 Uni-N */ - uninorth_node = find_devices("uni-n"); + uninorth_node = of_find_node_by_name(NULL, "uni-n"); + /* Locate G5 u3 */ + if (uninorth_node == NULL) { + uninorth_node = of_find_node_by_name(NULL, "u3"); + uninorth_u3 = 1; + } if (uninorth_node && uninorth_node->n_addrs > 0) { - uninorth_base = ioremap(uninorth_node->addrs[0].address, 0x4000); + unsigned long address = uninorth_node->addrs[0].address; + uninorth_base = ioremap(address, 0x40000); uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); + if (uninorth_u3) + u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); } else uninorth_node = NULL; if (!uninorth_node) return; - printk(KERN_INFO "Found Uninorth memory controller & host bridge, revision: %d\n", - uninorth_rev); + printk(KERN_INFO "Found %s memory controller & host bridge, revision: %d\n", + uninorth_u3 ? "U3" : "UniNorth", uninorth_rev); printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); /* Set the arbitrer QAck delay according to what Apple does @@ -2172,6 +2419,7 @@ probe_one_macio("mac-io", "paddington", macio_paddington); probe_one_macio("mac-io", "gatwick", macio_gatwick); probe_one_macio("mac-io", "heathrow", macio_heathrow); + probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2); /* Make sure the "main" macio chip appear first */ if (macio_chips[0].type == macio_gatwick @@ -2244,19 +2492,60 @@ MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); } +#ifdef CONFIG_POWER4 + if (macio_chips[0].type == macio_keylargo2) { +#ifndef CONFIG_SMP + /* On SMP machines running UP, we have the second CPU eating + * bus cycles. We need to take it off the bus. This is done + * from pmac_smp for SMP kernels running on one CPU + */ + np = of_find_node_by_type(NULL, "cpu"); + if (np != NULL) + np = of_find_node_by_type(np, "cpu"); + if (np != NULL) { + g5_phy_disable_cpu1(); + of_node_put(np); + } +#endif /* CONFIG_SMP */ + /* Enable GMAC for now for PCI probing. It will be disabled + * later on after PCI probe + */ + np = of_find_node_by_name(NULL, "ethernet"); + while(np) { + if (device_is_compatible(np, "K2-GMAC")) + g5_gmac_enable(np, 0, 1); + np = of_find_node_by_name(np, "ethernet"); + } + + /* Enable FW before PCI probe. Will be disabled later on + * Note: We should have a batter way to check that we are + * dealing with uninorth internal cell and not a PCI cell + * on the external PCI. The code below works though. + */ + np = of_find_node_by_name(NULL, "firewire"); + while(np) { + if (device_is_compatible(np, "pci106b,5811")) { + macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; + g5_fw_enable(np, 0, 1); + } + np = of_find_node_by_name(np, "firewire"); + } + } +#else /* CONFIG_POWER4 */ + if (macio_chips[0].type == macio_keylargo || macio_chips[0].type == macio_pangea || macio_chips[0].type == macio_intrepid) { /* Enable GMAC for now for PCI probing. It will be disabled * later on after PCI probe */ - np = find_devices("ethernet"); + np = of_find_node_by_name(NULL, "ethernet"); while(np) { if (np->parent && device_is_compatible(np->parent, "uni-north") && device_is_compatible(np, "gmac")) core99_gmac_enable(np, 0, 1); - np = np->next; + np = of_find_node_by_name(np, "ethernet"); } /* Enable FW before PCI probe. Will be disabled later on @@ -2264,7 +2553,7 @@ * dealing with uninorth internal cell and not a PCI cell * on the external PCI. The code below works though. */ - np = find_devices("firewire"); + np = of_find_node_by_name(NULL, "firewire"); while(np) { if (np->parent && device_is_compatible(np->parent, "uni-north") @@ -2274,18 +2563,18 @@ macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; core99_firewire_enable(np, 0, 1); } - np = np->next; + np = of_find_node_by_name(np, "firewire"); } /* Enable ATA-100 before PCI probe. */ - np = find_devices("ata-6"); + np = of_find_node_by_name(NULL, "ata-6"); while(np) { if (np->parent && device_is_compatible(np->parent, "uni-north") && device_is_compatible(np, "kauai-ata")) { core99_ata100_enable(np, 1); } - np = np->next; + np = of_find_node_by_name(np, "ata-6"); } /* Switch airport off */ @@ -2313,6 +2602,99 @@ MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N); } + /* Hack for bumping clock speed on the new PowerBooks and the + * iBook G4. This implements the "platform-do-clockspreading" OF + * property. For safety, we also check the product ID in the + * device-tree to make reasonably sure we won't set wrong values + * in the clock chip. + * + * Of course, ultimately, we have to implement a real parser for + * the platform-do-* stuff... + */ + while (machine_is_compatible("PowerBook5,2") || + machine_is_compatible("PowerBook5,3") || + machine_is_compatible("PowerBook6,2") || + machine_is_compatible("PowerBook6,3")) { + struct device_node *ui2c = of_find_node_by_type(NULL, "i2c"); + struct device_node *dt = of_find_node_by_name(NULL, "device-tree"); + u8 buffer[9]; + u32 *productID; + int i, rc, changed = 0; + + if (dt == NULL) + break; + productID = (u32 *)get_property(dt, "pid#", NULL); + if (productID == NULL) + break; + while(ui2c) { + struct device_node *p = of_get_parent(ui2c); + if (p && !strcmp(p->name, "uni-n")) + break; + ui2c = of_find_node_by_type(np, "i2c"); + } + if (ui2c == NULL) + break; + DBG("Trying to bump clock speed for PID: %08x...\n", *productID); + rc = pmac_low_i2c_open(ui2c, 1); + if (rc != 0) + break; + pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); + rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); + DBG("read result: %d,", rc); + if (rc != 0) { + pmac_low_i2c_close(ui2c); + break; + } + for (i=0; i<9; i++) + DBG(" %02x", buffer[i]); + DBG("\n"); + + switch(*productID) { + case 0x1182: /* AlBook 12" rev 2 */ + case 0x1183: /* iBook G4 12" */ + buffer[0] = (buffer[0] & 0x8f) | 0x70; + buffer[2] = (buffer[2] & 0x7f) | 0x00; + buffer[5] = (buffer[5] & 0x80) | 0x31; + buffer[6] = (buffer[6] & 0x40) | 0xb0; + buffer[7] = (buffer[7] & 0x00) | 0xc0; + buffer[8] = (buffer[8] & 0x00) | 0x30; + changed = 1; + break; + case 0x3142: /* AlBook 15" (ATI M10) */ + case 0x3143: /* AlBook 17" (ATI M10) */ + buffer[0] = (buffer[0] & 0xaf) | 0x50; + buffer[2] = (buffer[2] & 0x7f) | 0x00; + buffer[5] = (buffer[5] & 0x80) | 0x31; + buffer[6] = (buffer[6] & 0x40) | 0xb0; + buffer[7] = (buffer[7] & 0x00) | 0xd0; + buffer[8] = (buffer[8] & 0x00) | 0x30; + changed = 1; + break; + default: + DBG("i2c-hwclock: Machine model not handled\n"); + break; + } + if (!changed) { + pmac_low_i2c_close(ui2c); + break; + } + pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub); + rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9); + DBG("write result: %d,", rc); + pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); + rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); + DBG("read result: %d,", rc); + if (rc != 0) { + pmac_low_i2c_close(ui2c); + break; + } + for (i=0; i<9; i++) + DBG(" %02x", buffer[i]); + pmac_low_i2c_close(ui2c); + break; + } + +#endif /* CONFIG_POWER4 */ /* On all machines, switch modem & serial ports off */ np = find_devices("ch-a"); @@ -2339,6 +2721,9 @@ return; } + /* Setup low-level i2c stuffs */ + pmac_init_low_i2c(); + /* Probe machine type */ if (probe_motherboard()) printk(KERN_WARNING "Unknown PowerMac !\n"); @@ -2367,3 +2752,55 @@ } device_initcall(pmac_feature_late_init); + +#ifdef CONFIG_POWER4 + +static void dump_HT_speeds(char *name, u32 cfg, u32 frq) +{ + int freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 }; + int bits[8] = { 8,16,0,32,2,4,0,0 }; + int freq = (frq >> 8) & 0xf; + + if (freqs[freq] == 0) + printk("%s: Unknown HT link frequency %x\n", name, freq); + else + printk("%s: %d MHz on main link, (%d in / %d out) bits width\n", + name, freqs[freq], + bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]); +} + +void __init pmac_check_ht_link(void) +{ + u32 ufreq, freq, ucfg, cfg; + struct device_node *pcix_node; + u8 px_bus, px_devfn; + struct pci_controller *px_hose; + + (void)in_be32(u3_ht + U3_HT_LINK_COMMAND); + ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG); + ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ); + dump_HT_speeds("U3 HyperTransport", cfg, freq); + + pcix_node = of_find_compatible_node(NULL, "pci", "pci-x"); + if (pcix_node == NULL) { + printk("No PCI-X bridge found\n"); + return; + } + if (pci_device_from_OF_node(pcix_node, &px_bus, &px_devfn) != 0) { + printk("PCI-X bridge found but not matched to pci\n"); + return; + } + px_hose = pci_find_hose_for_OF_device(pcix_node); + if (px_hose == NULL) { + printk("PCI-X bridge found but not matched to host\n"); + return; + } + early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg); + early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq); + dump_HT_speeds("PCI-X HT Uplink", cfg, freq); + early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg); + early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq); + dump_HT_speeds("PCI-X HT Downlink", cfg, freq); +} + +#endif /* CONFIG_POWER4 */ --- diff/arch/ppc/platforms/pmac_nvram.c 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/ppc/platforms/pmac_nvram.c 2004-02-09 10:39:51.000000000 +0000 @@ -8,8 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Todo: - cleanup some coding horrors in the flash code - * - add support for the OF persistent properties + * Todo: - add support for the OF persistent properties */ #include #include @@ -21,29 +20,40 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #include #include #include #include -#include -#include -#undef DEBUG +#define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif #define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ #define CORE99_SIGNATURE 0x5a #define CORE99_ADLER_START 0x14 -/* Core99 nvram is a flash */ -#define CORE99_FLASH_STATUS_DONE 0x80 -#define CORE99_FLASH_STATUS_ERR 0x38 -#define CORE99_FLASH_CMD_ERASE_CONFIRM 0xd0 -#define CORE99_FLASH_CMD_ERASE_SETUP 0x20 -#define CORE99_FLASH_CMD_RESET 0xff -#define CORE99_FLASH_CMD_WRITE_SETUP 0x40 +/* On Core99, nvram is either a sharp, a micron or an AMD flash */ +#define SM_FLASH_STATUS_DONE 0x80 +#define SM_FLASH_STATUS_ERR 0x38 +#define SM_FLASH_CMD_ERASE_CONFIRM 0xd0 +#define SM_FLASH_CMD_ERASE_SETUP 0x20 +#define SM_FLASH_CMD_RESET 0xff +#define SM_FLASH_CMD_WRITE_SETUP 0x40 +#define SM_FLASH_CMD_CLEAR_STATUS 0x50 +#define SM_FLASH_CMD_READ_STATUS 0x70 /* CHRP NVRAM header */ struct chrp_header { @@ -70,21 +80,110 @@ static int nvram_mult, is_core_99; static int core99_bank = 0; static int nvram_partitions[3]; - -/* FIXME: kmalloc fails to allocate the image now that I had to move it - * before time_init(). For now, I allocate a static buffer here - * but it's a waste of space on all but core99 machines - */ -#if 0 -static char* nvram_image; -#else -static char nvram_image[NVRAM_SIZE] __pmacdata; -#endif +static spinlock_t nv_lock = SPIN_LOCK_UNLOCKED; extern int pmac_newworld; +extern int system_running; + +static int (*core99_write_bank)(int bank, u8* datas); +static int (*core99_erase_bank)(int bank); + +static char *nvram_image __pmacdata; + + +static unsigned char __pmac core99_nvram_read_byte(int addr) +{ + if (nvram_image == NULL) + return 0xff; + return nvram_image[addr]; +} + +static void __pmac core99_nvram_write_byte(int addr, unsigned char val) +{ + if (nvram_image == NULL) + return; + nvram_image[addr] = val; +} + + +static unsigned char __openfirmware direct_nvram_read_byte(int addr) +{ + return in_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]); +} + +static void __openfirmware direct_nvram_write_byte(int addr, unsigned char val) +{ + out_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult], val); +} + + +static unsigned char __pmac indirect_nvram_read_byte(int addr) +{ + unsigned char val; + unsigned long flags; + + spin_lock_irqsave(&nv_lock, flags); + out_8(nvram_addr, addr >> 5); + val = in_8(&nvram_data[(addr & 0x1f) << 4]); + spin_unlock_irqrestore(&nv_lock, flags); + + return val; +} + +static void __pmac indirect_nvram_write_byte(int addr, unsigned char val) +{ + unsigned long flags; + + spin_lock_irqsave(&nv_lock, flags); + out_8(nvram_addr, addr >> 5); + out_8(&nvram_data[(addr & 0x1f) << 4], val); + spin_unlock_irqrestore(&nv_lock, flags); +} + + +#ifdef CONFIG_ADB_PMU + +static void __pmac pmu_nvram_complete(struct adb_request *req) +{ + if (req->arg) + complete((struct completion *)req->arg); +} -static u8 __pmac -chrp_checksum(struct chrp_header* hdr) +static unsigned char __pmac pmu_nvram_read_byte(int addr) +{ + struct adb_request req; + DECLARE_COMPLETION(req_complete); + + req.arg = system_running ? &req_complete : NULL; + if (pmu_request(&req, pmu_nvram_complete, 3, PMU_READ_NVRAM, + (addr >> 8) & 0xff, addr & 0xff)) + return 0xff; + if (system_running) + wait_for_completion(&req_complete); + while (!req.complete) + pmu_poll(); + return req.reply[0]; +} + +static void __pmac pmu_nvram_write_byte(int addr, unsigned char val) +{ + struct adb_request req; + DECLARE_COMPLETION(req_complete); + + req.arg = system_running ? &req_complete : NULL; + if (pmu_request(&req, pmu_nvram_complete, 4, PMU_WRITE_NVRAM, + (addr >> 8) & 0xff, addr & 0xff, val)) + return; + if (system_running) + wait_for_completion(&req_complete); + while (!req.complete) + pmu_poll(); +} + +#endif /* CONFIG_ADB_PMU */ + + +static u8 __pmac chrp_checksum(struct chrp_header* hdr) { u8 *ptr; u16 sum = hdr->signature; @@ -95,8 +194,7 @@ return sum; } -static u32 __pmac -core99_calc_adler(u8 *buffer) +static u32 __pmac core99_calc_adler(u8 *buffer) { int cnt; u32 low, high; @@ -118,86 +216,186 @@ return (high << 16) | low; } -static u32 __pmac -core99_check(u8* datas) +static u32 __pmac core99_check(u8* datas) { struct core99_header* hdr99 = (struct core99_header*)datas; if (hdr99->hdr.signature != CORE99_SIGNATURE) { -#ifdef DEBUG - printk("Invalid signature\n"); -#endif + DBG("Invalid signature\n"); return 0; } if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) { -#ifdef DEBUG - printk("Invalid checksum\n"); -#endif + DBG("Invalid checksum\n"); return 0; } if (hdr99->adler != core99_calc_adler(datas)) { -#ifdef DEBUG - printk("Invalid adler\n"); -#endif + DBG("Invalid adler\n"); return 0; } return hdr99->generation; } -static int __pmac -core99_erase_bank(int bank) +static int __pmac sm_erase_bank(int bank) { int stat, i; + unsigned long timeout; u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; - out_8(base, CORE99_FLASH_CMD_ERASE_SETUP); - out_8(base, CORE99_FLASH_CMD_ERASE_CONFIRM); - do { stat = in_8(base); } - while(!(stat & CORE99_FLASH_STATUS_DONE)); - out_8(base, CORE99_FLASH_CMD_RESET); - if (stat & CORE99_FLASH_STATUS_ERR) { - printk("nvram: flash error 0x%02x on erase !\n", stat); - return -ENXIO; - } + DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank); + + out_8(base, SM_FLASH_CMD_ERASE_SETUP); + out_8(base, SM_FLASH_CMD_ERASE_CONFIRM); + timeout = 0; + do { + if (++timeout > 1000000) { + printk(KERN_ERR "nvram: Sharp/Miron flash erase timeout !\n"); + break; + } + out_8(base, SM_FLASH_CMD_READ_STATUS); + stat = in_8(base); + } while (!(stat & SM_FLASH_STATUS_DONE)); + + out_8(base, SM_FLASH_CMD_CLEAR_STATUS); + out_8(base, SM_FLASH_CMD_RESET); + for (i=0; i 1000000) { + printk(KERN_ERR "nvram: Sharp/Micron flash write timeout !\n"); + break; + } + out_8(base, SM_FLASH_CMD_READ_STATUS); + stat = in_8(base); + } while (!(stat & SM_FLASH_STATUS_DONE)); + if (!(stat & SM_FLASH_STATUS_DONE)) break; } - out_8(base, CORE99_FLASH_CMD_RESET); - if (stat & CORE99_FLASH_STATUS_ERR) { - printk("nvram: flash error 0x%02x on write !\n", stat); - return -ENXIO; + out_8(base, SM_FLASH_CMD_CLEAR_STATUS); + out_8(base, SM_FLASH_CMD_RESET); + for (i=0; i 1000000) { + printk(KERN_ERR "nvram: AMD flash erase timeout !\n"); + break; + } + stat = in_8(base) ^ in_8(base); + } while (stat != 0); + + /* Reset */ + out_8(base, 0xf0); + udelay(1); + + for (i=0; i 1000000) { + printk(KERN_ERR "nvram: AMD flash write timeout !\n"); + break; + } + stat = in_8(base) ^ in_8(base); + } while (stat != 0); + if (stat != 0) + break; } + + /* Reset */ + out_8(base, 0xf0); + udelay(1); + for (i=0; igeneration++; + hdr99->hdr.signature = CORE99_SIGNATURE; + hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr); + hdr99->adler = core99_calc_adler(nvram_image); + core99_bank = core99_bank ? 0 : 1; + if (core99_erase_bank) + if (core99_erase_bank(core99_bank)) { + printk("nvram: Error erasing bank %d\n", core99_bank); + goto bail; + } + if (core99_write_bank) + if (core99_write_bank(core99_bank, nvram_image)) + printk("nvram: Error writing bank %d\n", core99_bank); + bail: + spin_unlock_irqrestore(&nv_lock, flags); + #ifdef DEBUG - printk("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]); - printk("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]); - printk("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]); + mdelay(2000); #endif } -void __init -pmac_nvram_init(void) +void __init pmac_nvram_init(void) { struct device_node *dp; @@ -256,38 +488,65 @@ printk(KERN_ERR "nvram: no address\n"); return; } -#if 0 - nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL); - if (!nvram_image) { - printk(KERN_ERR "nvram: can't allocate image\n"); + nvram_image = alloc_bootmem(NVRAM_SIZE); + if (nvram_image == NULL) { + printk(KERN_ERR "nvram: can't allocate ram image\n"); return; } -#endif nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2); -#ifdef DEBUG - printk("nvram: Checking bank 0...\n"); -#endif + nvram_naddrs = 1; /* Make sure we get the correct case */ + + DBG("nvram: Checking bank 0...\n"); + gen_bank0 = core99_check((u8 *)nvram_data); gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE); core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0; -#ifdef DEBUG - printk("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1); - printk("nvram: Active bank is: %d\n", core99_bank); -#endif + + DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1); + DBG("nvram: Active bank is: %d\n", core99_bank); + for (i=0; iaddrs[0].address + isa_mem_base, dp->addrs[0].size); nvram_mult = 1; + ppc_md.nvram_read_val = direct_nvram_read_byte; + ppc_md.nvram_write_val = direct_nvram_write_byte; } else if (nvram_naddrs == 1) { nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size); nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE; + ppc_md.nvram_read_val = direct_nvram_read_byte; + ppc_md.nvram_write_val = direct_nvram_write_byte; } else if (nvram_naddrs == 2) { nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size); nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size); + ppc_md.nvram_read_val = indirect_nvram_read_byte; + ppc_md.nvram_write_val = indirect_nvram_write_byte; } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) { +#ifdef CONFIG_ADB_PMU nvram_naddrs = -1; + ppc_md.nvram_read_val = pmu_nvram_read_byte; + ppc_md.nvram_write_val = pmu_nvram_write_byte; +#endif /* CONFIG_ADB_PMU */ } else { printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n", nvram_naddrs); @@ -295,117 +554,31 @@ lookup_partitions(); } -void __pmac -pmac_nvram_update(void) -{ - struct core99_header* hdr99; - - if (!is_core_99 || !nvram_data || !nvram_image) - return; - if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE, - NVRAM_SIZE)) - return; -#ifdef DEBUG - printk("Updating nvram...\n"); -#endif - hdr99 = (struct core99_header*)nvram_image; - hdr99->generation++; - hdr99->hdr.signature = CORE99_SIGNATURE; - hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr); - hdr99->adler = core99_calc_adler(nvram_image); - core99_bank = core99_bank ? 0 : 1; - if (core99_erase_bank(core99_bank)) { - printk("nvram: Error erasing bank %d\n", core99_bank); - return; - } - if (core99_write_bank(core99_bank, nvram_image)) - printk("nvram: Error writing bank %d\n", core99_bank); -} - -unsigned char __pmac -pmac_nvram_read_byte(int addr) -{ - switch (nvram_naddrs) { -#ifdef CONFIG_ADB_PMU - case -1: { - struct adb_request req; - - if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM, - (addr >> 8) & 0xff, addr & 0xff)) - break; - while (!req.complete) - pmu_poll(); - return req.reply[0]; - } -#endif - case 1: - if (is_core_99) - return nvram_image[addr]; - return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]; - case 2: - *nvram_addr = addr >> 5; - eieio(); - return nvram_data[(addr & 0x1f) << 4]; - } - return 0; -} - -void __pmac -pmac_nvram_write_byte(int addr, unsigned char val) -{ - switch (nvram_naddrs) { -#ifdef CONFIG_ADB_PMU - case -1: { - struct adb_request req; - - if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM, - (addr >> 8) & 0xff, addr & 0xff, val)) - break; - while (!req.complete) - pmu_poll(); - break; - } -#endif - case 1: - if (is_core_99) { - nvram_image[addr] = val; - break; - } - nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val; - break; - case 2: - *nvram_addr = addr >> 5; - eieio(); - nvram_data[(addr & 0x1f) << 4] = val; - break; - } - eieio(); -} - -int __pmac -pmac_get_partition(int partition) +int __pmac pmac_get_partition(int partition) { return nvram_partitions[partition]; } -u8 __pmac -pmac_xpram_read(int xpaddr) +u8 __pmac pmac_xpram_read(int xpaddr) { int offset = nvram_partitions[pmac_nvram_XPRAM]; if (offset < 0) - return 0; + return 0xff; - return pmac_nvram_read_byte(xpaddr + offset); + return ppc_md.nvram_read_val(xpaddr + offset); } -void __pmac -pmac_xpram_write(int xpaddr, u8 data) +void __pmac pmac_xpram_write(int xpaddr, u8 data) { int offset = nvram_partitions[pmac_nvram_XPRAM]; if (offset < 0) return; - pmac_nvram_write_byte(data, xpaddr + offset); + ppc_md.nvram_write_val(xpaddr + offset, data); } + +EXPORT_SYMBOL(pmac_get_partition); +EXPORT_SYMBOL(pmac_xpram_read); +EXPORT_SYMBOL(pmac_xpram_write); --- diff/arch/ppc/platforms/pmac_pci.c 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/ppc/platforms/pmac_pci.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,13 +1,11 @@ /* * Support for PCI bridges found on Power Macintoshes. - * - * This includes support for bandit, chaos, grackle (motorola - * MPC106), and uninorth + * At present the "bandit" and "chaos" bridges are supported. + * Fortunately you access configuration space in the same + * way with either bridge. * * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au) * - * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org) - * * 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 @@ -30,11 +28,30 @@ #undef DEBUG -static void add_bridges(struct device_node *dev); +#ifdef DEBUG +#ifdef CONFIG_XMON +extern void xmon_printf(const char *fmt, ...); +#define DBG(x...) xmon_printf(x) +#else +#define DBG(x...) printk(x) +#endif +#else +#define DBG(x...) +#endif + +static int add_bridge(struct device_node *dev); +extern void pmac_check_ht_link(void); /* XXX Could be per-controller, but I don't think we risk anything by * assuming we won't have both UniNorth and Bandit */ static int has_uninorth; +#ifdef CONFIG_POWER4 +static struct pci_controller *u3_agp; +#endif /* CONFIG_POWER4 */ + +extern u8 pci_cache_line_size; + +struct pci_dev *k2_skiplist[2]; /* * Magic constants for enabling cache coherency in the bandit/PSX bridge. @@ -51,7 +68,7 @@ { for (; node != 0;node = node->sibling) { int * bus_range; - unsigned int *class_code; + unsigned int *class_code; int len; /* For PCI<->PCI bridges or CardBus bridges, we go down */ @@ -81,7 +98,7 @@ int * bus_range; int len; - /* Lookup the "bus-range" property for the hose */ + /* Lookup the "bus-range" property for the hose */ bus_range = (int *) get_property(bridge, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s\n", @@ -92,7 +109,7 @@ } /* - * Apple MacRISC (UniNorth, Bandit, Chaos) PCI controllers. + * Apple MacRISC (U3, 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 @@ -106,6 +123,11 @@ * 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. + * + * The U3 is the bridge used on G5 machines. It contains on + * AGP bus which is dealt with the old UniNorth access routines + * and an HyperTransport bus which uses its own set of access + * functions. */ #define MACRISC_CFA0(devfn, off) \ @@ -211,12 +233,22 @@ static int __pmac chaos_validate_dev(struct pci_bus *bus, int devfn, int offset) { - if (pci_busdev_to_OF_node(bus, devfn) == 0) + struct device_node *np; + u32 *vendor, *device; + + np = pci_busdev_to_OF_node(bus, devfn); + if (np == NULL) return PCIBIOS_DEVICE_NOT_FOUND; - if (/*(dev->vendor == 0x106b) && (dev->device == 3) &&*/ (offset >= 0x10) - && (offset != 0x14) && (offset != 0x18) && (offset <= 0x24)) { + + vendor = (u32 *)get_property(np, "vendor-id", NULL); + device = (u32 *)get_property(np, "device-id", NULL); + if (vendor == NULL || device == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + + if ((*vendor == 0x106b) && (*device == 3) && (offset >= 0x10) + && (offset != 0x14) && (offset != 0x18) && (offset <= 0x24)) return PCIBIOS_BAD_REGISTER_NUMBER; - } + return PCIBIOS_SUCCESSFUL; } @@ -248,6 +280,128 @@ chaos_write_config }; +#ifdef CONFIG_POWER4 + +/* + * These versions of U3 HyperTransport config space access ops do not + * implement self-view of the HT host yet + */ + +#define U3_HT_CFA0(devfn, off) \ + ((((unsigned long)devfn) << 8) | offset) +#define U3_HT_CFA1(bus, devfn, off) \ + (U3_HT_CFA0(devfn, off) \ + + (((unsigned long)bus) << 16) \ + + 0x01000000UL) + +static unsigned long __pmac +u3_ht_cfg_access(struct pci_controller* hose, u8 bus, u8 devfn, u8 offset) +{ + if (bus == hose->first_busno) { + /* For now, we don't self probe U3 HT bridge */ + if (PCI_FUNC(devfn) != 0 || PCI_SLOT(devfn) > 7 || + PCI_SLOT(devfn) < 1) + return 0; + return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset); + } else + return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset); +} + +static int __pmac +u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 *val) +{ + struct pci_controller *hose = bus->sysdata; + unsigned int addr; + int i; + + /* + * When a device in K2 is powered down, we die on config + * cycle accesses. Fix that here. + */ + for (i=0; i<2; i++) + if (k2_skiplist[i] && k2_skiplist[i]->bus == bus && + k2_skiplist[i]->devfn == devfn) { + switch (len) { + case 1: + *val = 0xff; break; + case 2: + *val = 0xffff; break; + default: + *val = 0xfffffffful; break; + } + return PCIBIOS_SUCCESSFUL; + } + + addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + *val = in_8((u8 *)addr); + break; + case 2: + *val = in_le16((u16 *)addr); + break; + default: + *val = in_le32((u32 *)addr); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int __pmac +u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 val) +{ + struct pci_controller *hose = bus->sysdata; + unsigned int addr; + int i; + + /* + * When a device in K2 is powered down, we die on config + * cycle accesses. Fix that here. + */ + for (i=0; i<2; i++) + if (k2_skiplist[i] && k2_skiplist[i]->bus == bus && + k2_skiplist[i]->devfn == devfn) + return PCIBIOS_SUCCESSFUL; + + addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + out_8((u8 *)addr, val); + (void) in_8((u8 *)addr); + break; + case 2: + out_le16((u16 *)addr, val); + (void) in_le16((u16 *)addr); + break; + default: + out_le32((u32 *)addr, val); + (void) in_le32((u32 *)addr); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops u3_ht_pci_ops = +{ + u3_ht_read_config, + u3_ht_write_config +}; + +#endif /* CONFIG_POWER4 */ /* * For a bandit bridge, turn on cache coherency if necessary. @@ -309,9 +463,7 @@ || strcmp(p2pbridge->parent->name, "pci") != 0) return; if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) { -#ifdef DEBUG - printk("Can't find PCI infos for PCI<->PCI bridge\n"); -#endif + DBG("Can't find PCI infos for PCI<->PCI bridge\n"); return; } /* Warning: At this point, we have not yet renumbered all busses. @@ -319,9 +471,7 @@ */ hose = pci_find_hose_for_OF_device(p2pbridge); if (!hose) { -#ifdef DEBUG - printk("Can't find hose for PCI<->PCI bridge\n"); -#endif + DBG("Can't find hose for PCI<->PCI bridge\n"); return; } if (early_read_config_word(hose, bus, devfn, @@ -333,13 +483,114 @@ early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val); } +/* + * Some Apple desktop machines have a NEC PD720100A USB2 controller + * on the motherboard. Open Firmware, on these, will disable the + * EHCI part of it so it behaves like a pair of OHCI's. This fixup + * code re-enables it ;) + */ +static void __init +fixup_nec_usb2(void) +{ + struct device_node *nec; + + for (nec = NULL; (nec = of_find_node_by_name(nec, "usb")) != NULL;) { + struct pci_controller *hose; + u32 data, *prop; + u8 bus, devfn; + + prop = (u32 *)get_property(nec, "vendor-id", NULL); + if (prop == NULL) + continue; + if (0x1033 != *prop) + continue; + prop = (u32 *)get_property(nec, "device-id", NULL); + if (prop == NULL) + continue; + if (0x0035 != *prop) + continue; + prop = (u32 *)get_property(nec, "reg", 0); + if (prop == NULL) + continue; + devfn = (prop[0] >> 8) & 0xff; + bus = (prop[0] >> 16) & 0xff; + if (PCI_FUNC(devfn) != 0) + continue; + hose = pci_find_hose_for_OF_device(nec); + if (!hose) + continue; + early_read_config_dword(hose, bus, devfn, 0xe4, &data); + if (data & 1UL) { + printk("Found NEC PD720100A USB2 chip with disabled EHCI, fixing up...\n"); + data &= ~1UL; + early_write_config_dword(hose, bus, devfn, 0xe4, data); + early_write_config_byte(hose, bus, devfn | 2, PCI_INTERRUPT_LINE, + nec->intrs[0].line); + } + } +} + void __init pmac_find_bridges(void) { - add_bridges(find_devices("bandit")); - add_bridges(find_devices("chaos")); - add_bridges(find_devices("pci")); + struct device_node *np, *root; + struct device_node *ht = NULL; + + root = of_find_node_by_path("/"); + if (root == NULL) { + printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n"); + return; + } + for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { + if (np->name == NULL) + continue; + if (strcmp(np->name, "bandit") == 0 + || strcmp(np->name, "chaos") == 0 + || strcmp(np->name, "pci") == 0) { + if (add_bridge(np) == 0) + of_node_get(np); + } + if (strcmp(np->name, "ht") == 0) { + of_node_get(np); + ht = np; + } + } + of_node_put(root); + + /* Probe HT last as it relies on the agp resources to be already + * setup + */ + if (ht && add_bridge(ht) != 0) + of_node_put(ht); + init_p2pbridge(); + fixup_nec_usb2(); +#ifdef CONFIG_POWER4 + /* There is something wrong with DMA on U3/HT. I haven't figured out + * the details yet, but if I set the cache line size to 128 bytes like + * it should, I'm getting memory corruption caused by devices like + * sungem (even without the MWI bit set, but maybe sungem doesn't + * care). Right now, it appears that setting up a 64 bytes line size + * works properly, 64 bytes beeing the max transfer size of HT, I + * suppose this is related the way HT/PCI are hooked together. I still + * need to dive into more specs though to be really sure of what's + * going on. --BenH. + * + * Ok, apparently, it's just that HT can't do more than 64 bytes + * transactions. MWI seem to be meaningless there as well, it may + * be worth nop'ing out pci_set_mwi too though I haven't done that + * yet. + * + * Note that it's a bit different for whatever is in the AGP slot. + * For now, I don't care, but this can become a real issue, we + * should probably hook pci_set_mwi anyway to make sure it sets + * the real cache line size in there. + */ + if (machine_is_compatible("MacRISC4")) + pci_cache_line_size = 16; /* 64 bytes */ + + pmac_check_ht_link(); +#endif /* CONFIG_POWER4 */ } #define GRACKLE_CFA(b, d, o) (0x80 | ((b) << 8) | ((d) << 16) \ @@ -410,6 +661,118 @@ ioremap(addr->address + 0xc00000, 0x1000); } +#ifdef CONFIG_POWER4 + +static void __init +setup_u3_agp(struct pci_controller* hose, struct reg_property* addr) +{ + /* On G5, we move AGP up to high bus number so we don't need + * to reassign bus numbers for HT. If we ever have P2P bridges + * on AGP, we'll have to move pci_assign_all_busses to the + * pci_controller structure so we enable it for AGP and not for + * HT childs. + * We hard code the address because of the different size of + * the reg address cell, we shall fix that by killing struct + * reg_property and using some accessor functions instead + */ + hose->first_busno = 0xf0; + hose->last_busno = 0xff; + has_uninorth = 1; + hose->ops = ¯isc_pci_ops; + hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); + hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); + + u3_agp = hose; +} + +static void __init +setup_u3_ht(struct pci_controller* hose, struct reg_property *addr) +{ + struct device_node *np = (struct device_node *)hose->arch_data; + int i, cur; + + hose->ops = &u3_ht_pci_ops; + + /* We hard code the address because of the different size of + * the reg address cell, we shall fix that by killing struct + * reg_property and using some accessor functions instead + */ + hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000, 0x02000000); + + /* + * /ht node doesn't expose a "ranges" property, so we "remove" regions that + * have been allocated to AGP. So far, this version of the code doesn't assign + * any of the 0xfxxxxxxx "fine" memory regions to /ht. + * We need to fix that sooner or later by either parsing all child "ranges" + * properties or figuring out the U3 address space decoding logic and + * then read it's configuration register (if any). + */ + hose->io_base_phys = 0xf4000000 + 0x00400000; + hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000); + isa_io_base = (unsigned long) hose->io_base_virt; + hose->io_resource.name = np->full_name; + hose->io_resource.start = 0; + hose->io_resource.end = 0x003fffff; + hose->io_resource.flags = IORESOURCE_IO; + hose->pci_mem_offset = 0; + hose->first_busno = 0; + hose->last_busno = 0xef; + hose->mem_resources[0].name = np->full_name; + hose->mem_resources[0].start = 0x80000000; + hose->mem_resources[0].end = 0xefffffff; + hose->mem_resources[0].flags = IORESOURCE_MEM; + + if (u3_agp == NULL) { + DBG("U3 has no AGP, using full resource range\n"); + return; + } + + /* We "remove" the AGP resources from the resources allocated to HT, that + * is we create "holes". However, that code does assumptions that so far + * happen to be true (cross fingers...), typically that resources in the + * AGP node are properly ordered + */ + cur = 0; + for (i=0; i<3; i++) { + struct resource *res = &u3_agp->mem_resources[i]; + if (res->flags != IORESOURCE_MEM) + continue; + /* We don't care about "fine" resources */ + if (res->start >= 0xf0000000) + continue; + /* Check if it's just a matter of "shrinking" us in one direction */ + if (hose->mem_resources[cur].start == res->start) { + DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n", + cur, hose->mem_resources[cur].start, res->end + 1); + hose->mem_resources[cur].start = res->end + 1; + continue; + } + if (hose->mem_resources[cur].end == res->end) { + DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n", + cur, hose->mem_resources[cur].end, res->start - 1); + hose->mem_resources[cur].end = res->start - 1; + continue; + } + /* No, it's not the case, we need a hole */ + if (cur == 2) { + /* not enough resources to make a hole, we drop part of the range */ + printk(KERN_WARNING "Running out of resources for /ht host !\n"); + hose->mem_resources[cur].end = res->start - 1; + continue; + } + cur++; + DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", + cur-1, res->start - 1, cur, res->end + 1); + hose->mem_resources[cur].name = np->full_name; + hose->mem_resources[cur].flags = IORESOURCE_MEM; + hose->mem_resources[cur].start = res->end + 1; + hose->mem_resources[cur].end = hose->mem_resources[cur-1].end; + hose->mem_resources[cur-1].end = res->start - 1; + } +} + +#endif /* CONFIG_POWER4 */ + void __init setup_grackle(struct pci_controller *hose) { @@ -426,69 +789,77 @@ * "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 int __init +add_bridge(struct device_node *dev) { int len; struct pci_controller *hose; struct reg_property *addr; char* disp_name; int *bus_range; - int first = 1, primary; + int primary = 1; - for (; dev != NULL; dev = dev->next) { - addr = (struct reg_property *) get_property(dev, "reg", &len); - if (addr == NULL || len < sizeof(*addr)) { - printk(KERN_WARNING "Can't use %s: no address\n", - dev->full_name); - continue; - } - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", - dev->full_name); - } - - hose = pcibios_alloc_controller(); - if (!hose) - continue; - hose->arch_data = dev; - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; - - disp_name = NULL; - primary = first; - if (device_is_compatible(dev, "uni-north")) { - primary = setup_uninorth(hose, addr); - disp_name = "UniNorth"; - } else if (strcmp(dev->name, "pci") == 0) { - /* XXX assume this is a mpc106 (grackle) */ - setup_grackle(hose); - disp_name = "Grackle (MPC106)"; - } else if (strcmp(dev->name, "bandit") == 0) { - setup_bandit(hose, addr); - disp_name = "Bandit"; - } else if (strcmp(dev->name, "chaos") == 0) { - setup_chaos(hose, addr); - disp_name = "Chaos"; - primary = 0; - } - printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n", - disp_name, addr->address, hose->first_busno, hose->last_busno); -#ifdef DEBUG - printk(" ->Hose at 0x%08lx, cfg_addr=0x%08lx,cfg_data=0x%08lx\n", - hose, hose->cfg_addr, hose->cfg_data); -#endif - - /* Interpret the "ranges" property */ - /* This also maps the I/O region and sets isa_io/mem_base */ - pci_process_bridge_OF_ranges(hose, dev, primary); + DBG("Adding PCI host bridge %s\n", dev->full_name); - /* Fixup "bus-range" OF property */ - fixup_bus_range(dev); + addr = (struct reg_property *) get_property(dev, "reg", &len); + if (addr == NULL || len < sizeof(*addr)) { + printk(KERN_WARNING "Can't use %s: no address\n", + dev->full_name); + return -ENODEV; + } + bus_range = (int *) get_property(dev, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", + dev->full_name); + } + + hose = pcibios_alloc_controller(); + if (!hose) + return -ENOMEM; + hose->arch_data = dev; + hose->first_busno = bus_range ? bus_range[0] : 0; + hose->last_busno = bus_range ? bus_range[1] : 0xff; + + disp_name = NULL; +#ifdef CONFIG_POWER4 + if (device_is_compatible(dev, "u3-agp")) { + setup_u3_agp(hose, addr); + disp_name = "U3-AGP"; + primary = 0; + } else if (device_is_compatible(dev, "u3-ht")) { + setup_u3_ht(hose, addr); + disp_name = "U3-HT"; + primary = 1; + } else +#endif /* CONFIG_POWER4 */ + if (device_is_compatible(dev, "uni-north")) { + primary = setup_uninorth(hose, addr); + disp_name = "UniNorth"; + } else if (strcmp(dev->name, "pci") == 0) { + /* XXX assume this is a mpc106 (grackle) */ + setup_grackle(hose); + disp_name = "Grackle (MPC106)"; + } else if (strcmp(dev->name, "bandit") == 0) { + setup_bandit(hose, addr); + disp_name = "Bandit"; + } else if (strcmp(dev->name, "chaos") == 0) { + setup_chaos(hose, addr); + disp_name = "Chaos"; + primary = 0; + } + printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n", + disp_name, addr->address, hose->first_busno, hose->last_busno); + DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n", + hose, hose->cfg_addr, hose->cfg_data); + + /* Interpret the "ranges" property */ + /* This also maps the I/O region and sets isa_io/mem_base */ + pci_process_bridge_OF_ranges(hose, dev, primary); - first &= !primary; - } + /* Fixup "bus-range" OF property */ + fixup_bus_range(dev); + + return 0; } static void __init @@ -575,7 +946,7 @@ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; pci_write_config_word(dev, PCI_COMMAND, cmd); pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16); - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size); } return 0; @@ -628,3 +999,108 @@ } } +void pmac_pci_fixup_cardbus(struct pci_dev* dev) +{ + if (_machine != _MACH_Pmac) + return; + /* + * Fix the interrupt routing on the various cardbus bridges + * used on powerbooks + */ + if (dev->vendor != PCI_VENDOR_ID_TI) + return; + if (dev->device == PCI_DEVICE_ID_TI_1130 || + dev->device == PCI_DEVICE_ID_TI_1131) { + u8 val; + /* Enable PCI interrupt */ + if (pci_read_config_byte(dev, 0x91, &val) == 0) + pci_write_config_byte(dev, 0x91, val | 0x30); + /* Disable ISA interrupt mode */ + if (pci_read_config_byte(dev, 0x92, &val) == 0) + pci_write_config_byte(dev, 0x92, val & ~0x06); + } + if (dev->device == PCI_DEVICE_ID_TI_1210 || + dev->device == PCI_DEVICE_ID_TI_1211 || + dev->device == PCI_DEVICE_ID_TI_1410 || + dev->device == PCI_DEVICE_ID_TI_1510) { + u8 val; + /* 0x8c == TI122X_IRQMUX, 2 says to route the INTA + signal out the MFUNC0 pin */ + if (pci_read_config_byte(dev, 0x8c, &val) == 0) + pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2); + /* Disable ISA interrupt mode */ + if (pci_read_config_byte(dev, 0x92, &val) == 0) + pci_write_config_byte(dev, 0x92, val & ~0x06); + } +} + +void pmac_pci_fixup_pciata(struct pci_dev* dev) +{ + u8 progif = 0; + + /* + * On PowerMacs, we try to switch any PCI ATA controller to + * fully native mode + */ + if (_machine != _MACH_Pmac) + return; + /* Some controllers don't have the class IDE */ + if (dev->vendor == PCI_VENDOR_ID_PROMISE) + switch(dev->device) { + case PCI_DEVICE_ID_PROMISE_20246: + case PCI_DEVICE_ID_PROMISE_20262: + case PCI_DEVICE_ID_PROMISE_20263: + case PCI_DEVICE_ID_PROMISE_20265: + case PCI_DEVICE_ID_PROMISE_20267: + case PCI_DEVICE_ID_PROMISE_20268: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20270: + case PCI_DEVICE_ID_PROMISE_20271: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20277: + goto good; + } + /* Others, check PCI class */ + if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) + return; + good: + pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); + if ((progif & 5) != 5) { + printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", pci_name(dev)); + (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5); + if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || + (progif & 5) != 5) + printk(KERN_ERR "Rewrite of PROGIF failed !\n"); + } +} + +/* + * Disable second function on K2-SATA, it's broken + * and disable IO BARs on first one + */ +void __pmac pmac_pci_fixup_k2_sata(struct pci_dev* dev) +{ + int i; + u16 cmd; + + if (PCI_FUNC(dev->devfn) > 0) { + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_write_config_word(dev, PCI_COMMAND, cmd); + for (i = 0; i < 6; i++) { + dev->resource[i].start = dev->resource[i].end = 0; + dev->resource[i].flags = 0; + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); + } + } else { + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd &= ~PCI_COMMAND_IO; + pci_write_config_word(dev, PCI_COMMAND, cmd); + for (i = 0; i < 5; i++) { + dev->resource[i].start = dev->resource[i].end = 0; + dev->resource[i].flags = 0; + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); + } + } +} --- diff/arch/ppc/platforms/pmac_pic.c 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/ppc/platforms/pmac_pic.c 2004-02-09 10:39:51.000000000 +0000 @@ -34,6 +34,7 @@ #include #include #include +#include #include "pmac_pic.h" @@ -363,32 +364,76 @@ return irqctrler->intrs[0].line; } -void __init -pmac_pic_init(void) +#ifdef CONFIG_POWER4 +static irqreturn_t k2u3_action(int cpl, void *dev_id, struct pt_regs *regs) +{ + int irq; + + irq = openpic2_get_irq(regs); + if (irq != -1) + ppc_irq_dispatch_handler(regs, irq); + return IRQ_HANDLED; +} +#endif /* CONFIG_POWER4 */ + +void __init pmac_pic_init(void) { int i; - struct device_node *irqctrler; + struct device_node *irqctrler = NULL; + struct device_node *irqctrler2 = NULL; + struct device_node *np; unsigned long addr; int irq_cascade = -1; /* We first try to detect Apple's new Core99 chipset, since mac-io * is quite different on those machines and contains an IBM MPIC2. */ - irqctrler = find_type_devices("open-pic"); + np = find_type_devices("open-pic"); + while(np) { + if (np->parent && !strcmp(np->parent->name, "u3")) + irqctrler2 = np; + else + irqctrler = np; + np = np->next; + } if (irqctrler != NULL) { - printk("PowerMac using OpenPIC irq controller\n"); if (irqctrler->n_addrs > 0) { - unsigned char senses[NR_IRQS]; + unsigned char senses[128]; + + printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", + irqctrler->addrs[0].address); - prom_get_irq_senses(senses, 0, NR_IRQS); + prom_get_irq_senses(senses, 0, 128); OpenPIC_InitSenses = senses; - OpenPIC_NumInitSenses = NR_IRQS; + OpenPIC_NumInitSenses = 128; ppc_md.get_irq = openpic_get_irq; + pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0); OpenPIC_Addr = ioremap(irqctrler->addrs[0].address, irqctrler->addrs[0].size); openpic_init(0); + +#ifdef CONFIG_POWER4 + if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 && + irqctrler2->n_addrs > 0) { + printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n", + irqctrler2->addrs[0].address, + irqctrler2->intrs[0].line); + pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0); + OpenPIC2_Addr = ioremap(irqctrler2->addrs[0].address, + irqctrler2->addrs[0].size); + prom_get_irq_senses(senses, PMAC_OPENPIC2_OFFSET, + PMAC_OPENPIC2_OFFSET+128); + OpenPIC_InitSenses = senses; + OpenPIC_NumInitSenses = 128; + openpic2_init(PMAC_OPENPIC2_OFFSET); + if (request_irq(irqctrler2->intrs[0].line, k2u3_action, 0, + "U3->K2 Cascade", NULL)) + printk("Unable to get OpenPIC IRQ for cascade\n"); + } +#endif /* CONFIG_POWER4 */ + #ifdef CONFIG_XMON { struct device_node* pswitch; --- diff/arch/ppc/platforms/pmac_setup.c 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/ppc/platforms/pmac_setup.c 2004-02-09 10:39:51.000000000 +0000 @@ -332,7 +332,7 @@ #ifdef CONFIG_SMP /* Check for Core99 */ - if (find_devices("uni-n")) + if (find_devices("uni-n") || find_devices("u3")) ppc_md.smp_ops = &core99_smp_ops; else ppc_md.smp_ops = &psurge_smp_ops; @@ -469,10 +469,6 @@ struct adb_request req; #endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_NVRAM - pmac_nvram_update(); -#endif - switch (sys_ctrler) { #ifdef CONFIG_ADB_CUDA case SYS_CTRLER_CUDA: @@ -498,10 +494,6 @@ struct adb_request req; #endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_NVRAM - pmac_nvram_update(); -#endif - switch (sys_ctrler) { #ifdef CONFIG_ADB_CUDA case SYS_CTRLER_CUDA: @@ -637,11 +629,6 @@ ppc_md.get_rtc_time = pmac_get_rtc_time; ppc_md.calibrate_decr = pmac_calibrate_decr; -#ifdef CONFIG_NVRAM - ppc_md.nvram_read_val = pmac_nvram_read_byte; - ppc_md.nvram_write_val = pmac_nvram_write_byte; -#endif - ppc_md.find_end_of_memory = pmac_find_end_of_memory; ppc_md.feature_call = pmac_do_feature_call; @@ -685,6 +672,14 @@ break; } } + np = find_devices("u3"); + if (np) { + for (np = np->child; np != NULL; np = np->sibling) + if (strncmp(np->name, "i2c", 3) == 0) { + of_platform_device_create(np, "u3-i2c"); + break; + } + } np = find_devices("valkyrie"); if (np) --- diff/arch/ppc/platforms/pmac_smp.c 2003-10-27 09:20:37.000000000 +0000 +++ source/arch/ppc/platforms/pmac_smp.c 2004-02-09 10:39:51.000000000 +0000 @@ -119,8 +119,7 @@ /* Sync flag for HW tb sync */ static volatile int sec_tb_reset = 0; -static void __init -core99_init_caches(int cpu) +static void __init core99_init_caches(int cpu) { if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR)) return; @@ -188,8 +187,7 @@ */ static unsigned long psurge_smp_message[NR_CPUS]; -void __pmac -psurge_smp_message_recv(struct pt_regs *regs) +void __pmac psurge_smp_message_recv(struct pt_regs *regs) { int cpu = smp_processor_id(); int msg; @@ -206,15 +204,14 @@ smp_message_recv(msg, regs); } -irqreturn_t __pmac -psurge_primary_intr(int irq, void *d, struct pt_regs *regs) +irqreturn_t __pmac psurge_primary_intr(int irq, void *d, struct pt_regs *regs) { psurge_smp_message_recv(regs); return IRQ_HANDLED; } -static void __pmac -smp_psurge_message_pass(int target, int msg, unsigned long data, int wait) +static void __pmac smp_psurge_message_pass(int target, int msg, unsigned long data, + int wait) { int i; @@ -410,8 +407,7 @@ smp_tb_synchronized = 1; } -static void __init -smp_psurge_setup_cpu(int cpu_nr) +static void __init smp_psurge_setup_cpu(int cpu_nr) { if (cpu_nr == 0) { @@ -435,41 +431,54 @@ psurge_dual_sync_tb(cpu_nr); } -void __init -smp_psurge_take_timebase(void) +void __init smp_psurge_take_timebase(void) { /* Dummy implementation */ } -void __init -smp_psurge_give_timebase(void) +void __init smp_psurge_give_timebase(void) { /* Dummy implementation */ } -static int __init -smp_core99_probe(void) +static int __init smp_core99_probe(void) { +#ifdef CONFIG_6xx extern int powersave_nap; - struct device_node *cpus; - int i, ncpus = 1; +#endif + struct device_node *cpus, *firstcpu; + int i, ncpus = 0, boot_cpu = -1; u32 *tbprop; if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); - cpus = find_type_devices("cpu"); - if (cpus == NULL) - return 0; - - tbprop = (u32 *)get_property(cpus, "timebase-enable", NULL); - if (tbprop) - core99_tb_gpio = *tbprop; - else - core99_tb_gpio = KL_GPIO_TB_ENABLE; + cpus = firstcpu = find_type_devices("cpu"); + while(cpus != NULL) { + u32 *regprop = (u32 *)get_property(cpus, "reg", NULL); + char *stateprop = (char *)get_property(cpus, "state", NULL); + if (regprop != NULL && stateprop != NULL && + !strncmp(stateprop, "running", 7)) + boot_cpu = *regprop; + ++ncpus; + cpus = cpus->next; + } + if (boot_cpu == -1) + printk(KERN_WARNING "Couldn't detect boot CPU !\n"); + if (boot_cpu != 0) + printk(KERN_WARNING "Boot CPU is %d, unsupported setup !\n", boot_cpu); - while ((cpus = cpus->next) != NULL) - ++ncpus; + if (machine_is_compatible("MacRISC4")) { + extern struct smp_ops_t core99_smp_ops; - printk("smp_core99_probe: found %d cpus\n", ncpus); + core99_smp_ops.take_timebase = smp_generic_take_timebase; + core99_smp_ops.give_timebase = smp_generic_give_timebase; + } else { + if (firstcpu != NULL) + tbprop = (u32 *)get_property(firstcpu, "timebase-enable", NULL); + if (tbprop) + core99_tb_gpio = *tbprop; + else + core99_tb_gpio = KL_GPIO_TB_ENABLE; + } if (ncpus > 1) { openpic_request_IPIs(); @@ -484,8 +493,7 @@ return ncpus; } -static void __init -smp_core99_kick_cpu(int nr) +static void __init smp_core99_kick_cpu(int nr) { unsigned long save_vector, new_vector; unsigned long flags; @@ -539,23 +547,31 @@ if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347); } -static void __init -smp_core99_setup_cpu(int cpu_nr) +static void __init smp_core99_setup_cpu(int cpu_nr) { - /* Setup some registers */ + /* Setup L2/L3 */ if (cpu_nr != 0) core99_init_caches(cpu_nr); /* Setup openpic */ do_openpic_setup_cpu(); - /* Setup L2/L3 */ - if (cpu_nr == 0) + if (cpu_nr == 0) { +#ifdef CONFIG_POWER4 + extern void g5_phy_disable_cpu1(void); + + /* If we didn't start the second CPU, we must take + * it off the bus + */ + if (machine_is_compatible("MacRISC4") && + num_online_cpus() < 2) + g5_phy_disable_cpu1(); +#endif /* CONFIG_POWER4 */ if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349); + } } -void __init -smp_core99_take_timebase(void) +void __init smp_core99_take_timebase(void) { /* Secondary processor "takes" the timebase by freezing * it, resetting its local TB and telling CPU 0 to go on @@ -572,8 +588,7 @@ sec_tb_reset = 1; } -void __init -smp_core99_give_timebase(void) +void __init smp_core99_give_timebase(void) { unsigned int t; --- diff/arch/ppc/platforms/pmac_time.c 2003-10-27 09:20:37.000000000 +0000 +++ source/arch/ppc/platforms/pmac_time.c 2004-02-09 10:39:51.000000000 +0000 @@ -266,6 +266,14 @@ if (via_calibrate_decr()) return; + /* Special case: QuickSilver G4s seem to have a badly calibrated + * timebase-frequency in OF, VIA is much better on these. We should + * probably implement calibration based on the KL timer on these + * machines anyway... -BenH + */ + if (machine_is_compatible("PowerMac3,5")) + if (via_calibrate_decr()) + return; /* * The cpu node should have a timebase-frequency property * to tell us the rate at which the decrementer counts. --- diff/arch/ppc/platforms/sandpoint.c 2003-09-17 12:28:03.000000000 +0100 +++ source/arch/ppc/platforms/sandpoint.c 2004-02-09 10:39:51.000000000 +0000 @@ -103,12 +103,10 @@ #include #include #include +#include #include "sandpoint.h" -extern void gen550_progress(char *, unsigned short); -extern void gen550_init(int, struct uart_port *); - unsigned char __res[sizeof(bd_t)]; static void sandpoint_halt(void); @@ -706,6 +704,9 @@ #if defined(CONFIG_SERIAL_8250) && \ (defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)) sandpoint_early_serial_map(); +#ifdef CONFIG_KGDB + ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; +#endif #ifdef CONFIG_SERIAL_TEXT_DEBUG ppc_md.progress = gen550_progress; #endif --- diff/arch/ppc/syslib/Makefile 2003-09-17 12:28:03.000000000 +0100 +++ source/arch/ppc/syslib/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -31,6 +31,7 @@ endif obj-$(CONFIG_PPC_OF) += prom_init.o prom.o of_device.o obj-$(CONFIG_PPC_PMAC) += open_pic.o indirect_pci.o +obj-$(CONFIG_POWER4) += open_pic2.o obj-$(CONFIG_PPC_CHRP) += open_pic.o indirect_pci.o i8259.o obj-$(CONFIG_PPC_PREP) += open_pic.o indirect_pci.o i8259.o obj-$(CONFIG_ADIR) += i8259.o indirect_pci.o pci_auto.o \ @@ -66,7 +67,7 @@ obj-$(CONFIG_SPRUCE) += cpc700_pic.o indirect_pci.o pci_auto.o \ todc_time.o obj-$(CONFIG_8260) += m8260_setup.o ppc8260_pic.o -ifeq ($(CONFIG_SERIAL_8250)$(CONFIG_PPC_GEN550),yy) +ifeq ($(CONFIG_PPC_GEN550),y) obj-$(CONFIG_KGDB) += gen550_kgdb.o gen550_dbg.o obj-$(CONFIG_SERIAL_TEXT_DEBUG) += gen550_dbg.o endif --- diff/arch/ppc/syslib/gen550_dbg.c 2003-07-11 09:39:50.000000000 +0100 +++ source/arch/ppc/syslib/gen550_dbg.c 2004-02-09 10:39:51.000000000 +0000 @@ -17,6 +17,8 @@ */ #include +#include +#include #include /* For linux/serial_core.h */ #include #include --- diff/arch/ppc/syslib/gen550_kgdb.c 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/ppc/syslib/gen550_kgdb.c 2004-02-09 10:39:51.000000000 +0000 @@ -77,7 +77,7 @@ * to use. */ void -kgdb_map_scc(void) +gen550_kgdb_map_scc(void) { printk(KERN_DEBUG "kgdb init\n"); kgdb_debugport = serial_init(KGDB_PORT, NULL); --- diff/arch/ppc/syslib/of_device.c 2003-10-27 09:20:37.000000000 +0000 +++ source/arch/ppc/syslib/of_device.c 2004-02-09 10:39:51.000000000 +0000 @@ -183,6 +183,7 @@ struct of_device *ofdev; ofdev = to_of_device(dev); + of_node_put(ofdev->node); kfree(ofdev); } @@ -242,7 +243,7 @@ return NULL; memset(dev, 0, sizeof(*dev)); - dev->node = np; + dev->node = of_node_get(np); dev->dma_mask = 0xffffffffUL; dev->dev.dma_mask = &dev->dma_mask; dev->dev.parent = NULL; --- diff/arch/ppc/syslib/open_pic.c 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/ppc/syslib/open_pic.c 2004-02-09 10:39:51.000000000 +0000 @@ -610,12 +610,15 @@ void __devinit do_openpic_setup_cpu(void) { +#ifdef CONFIG_IRQ_ALL_CPUS int i; - u32 msk = 1 << smp_hw_index[smp_processor_id()]; - + u32 msk; +#endif spin_lock(&openpic_setup_lock); #ifdef CONFIG_IRQ_ALL_CPUS + msk = 1 << smp_hw_index[smp_processor_id()]; + /* let the openpic know we want intrs. default affinity * is 0xffffffff until changed via /proc * That's how it's done on x86. If we want it differently, then @@ -788,15 +791,25 @@ */ static void openpic_ack_irq(unsigned int irq_nr) { +#ifdef __SLOW_VERSION__ openpic_disable_irq(irq_nr); openpic_eoi(); +#else + if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0) + openpic_eoi(); +#endif } static void openpic_end_irq(unsigned int irq_nr) { +#ifdef __SLOW_VERSION__ if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && irq_desc[irq_nr].action) openpic_enable_irq(irq_nr); +#else + if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0) + openpic_eoi(); +#endif } static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask) --- diff/arch/ppc/syslib/prom.c 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/ppc/syslib/prom.c 2004-02-09 10:39:51.000000000 +0000 @@ -160,7 +160,7 @@ match on /chosen.interrupt_controller */ if ((name != NULL && strcmp(name, "interrupt-controller") == 0) - || (ic != NULL && iclen == 0)) { + || (ic != NULL && iclen == 0 && strcmp(name, "AppleKiwi"))) { if (n == 0) dflt_interrupt_controller = np; ++n; @@ -217,7 +217,7 @@ ifunc = interpret_macio_props; else if (!strcmp(np->type, "isa")) ifunc = interpret_isa_props; - else if (!strcmp(np->name, "uni-n")) + else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3")) ifunc = interpret_root_props; else if (!((ifunc == interpret_dbdma_props || ifunc == interpret_macio_props) @@ -431,10 +431,21 @@ * This doesn't cope with the general case of multiple * cascaded interrupt controllers, but then neither will * irq.c at the moment either. -- paulus + * The G5 triggers that code, I add a machine test. On + * those machines, we want to offset interrupts from the + * second openpic by 128 -- BenH */ - if (num_interrupt_controllers > 1 && ic != NULL + if (_machine != _MACH_Pmac && num_interrupt_controllers > 1 + && ic != NULL && get_property(ic, "interrupt-parent", NULL) == NULL) offset = 16; + else if (_machine == _MACH_Pmac && num_interrupt_controllers > 1 + && ic != NULL && ic->parent != NULL) { + char *name = get_property(ic->parent, "name", NULL); + if (name && !strcmp(name, "u3")) + offset = 128; + } + np->intrs[i].line = irq[0] + offset; if (n > 1) np->intrs[i].sense = irq[1]; @@ -1212,8 +1223,6 @@ * Request an OF device resource. Currently handles child of PCI devices, * or other nodes attached to the root node. Ultimately, put some * link to resources in the OF node. - * WARNING: out_resource->name should be initialized before calling this - * function. */ struct resource* __openfirmware request_OF_resource(struct device_node* node, int index, const char* name_postfix) @@ -1276,7 +1285,7 @@ { struct pci_dev* pcidev; u8 pci_bus, pci_devfn; - unsigned long iomask; + unsigned long iomask, start, end; struct device_node* nd; struct resource* parent; struct resource *res = NULL; @@ -1305,18 +1314,23 @@ if (pcidev) parent = find_parent_pci_resource(pcidev, &node->addrs[index]); if (!parent) { - printk(KERN_WARNING "request_OF_resource(%s), parent not found\n", + printk(KERN_WARNING "release_OF_resource(%s), parent not found\n", node->name); return -ENODEV; } - /* Find us in the parent */ + /* Find us in the parent and its childs */ res = parent->child; + start = node->addrs[index].address; + end = start + node->addrs[index].size - 1; while (res) { - if (res->start == node->addrs[index].address && - res->end == (res->start + node->addrs[index].size - 1)) + if (res->start == start && res->end == end && + (res->flags & IORESOURCE_BUSY)) break; - res = res->sibling; + if (res->start <= start && res->end >= end) + res = res->child; + else + res = res->sibling; } if (!res) return -ENODEV; --- diff/arch/ppc/syslib/prom_init.c 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/ppc/syslib/prom_init.c 2004-02-09 10:39:51.000000000 +0000 @@ -260,6 +260,74 @@ } } +#ifdef CONFIG_POWER4 +/* + * Set up a hash table with a set of entries in it to map the + * first 64MB of RAM. This is used on 64-bit machines since + * some of them don't have BATs. + */ + +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, vsid; + + 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] = vsid | ((va >> 16) & 0xf80) | 1; + pteg[3] = pa | mode; + break; + } + } +} + +extern unsigned long _SDR1; +extern PTE *Hash; +extern unsigned long Hash_size; + +static void __init +prom_alloc_htab(void) +{ + unsigned int hsize; + unsigned long htab; + unsigned int addr; + + /* + * Because of OF bugs we can't use the "claim" client + * interface to allocate memory for the hash table. + * This code is only used on 64-bit PPCs, and the only + * 64-bit PPCs at the moment are RS/6000s, and their + * OF is based at 0xc00000 (the 12M point), so we just + * arbitrarily use the 0x800000 - 0xc00000 region for the + * hash table. + * -- paulus. + */ + hsize = 4 << 20; /* POWER4 has no BATs */ + htab = (8 << 20); + call_prom("claim", 3, 1, htab, hsize, 0); + Hash = (void *)(htab + KERNELBASE); + Hash_size = hsize; + _SDR1 = htab + __ilog2(hsize) - 18; + + /* + * Put in PTEs for the first 64MB of RAM + */ + memset((void *)htab, 0, hsize); + for (addr = 0; addr < 0x4000000; addr += 0x1000) + make_pte(htab, hsize, addr + KERNELBASE, addr, + _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX); +#if 0 /* DEBUG stuff mapping the SCC */ + make_pte(htab, hsize, 0x80013000, 0x80013000, + _PAGE_ACCESSED | _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX); +#endif +} +#endif /* CONFIG_POWER4 */ + + /* * If we have a display that we don't know how to drive, * we will want to try to execute OF's open method for it @@ -434,13 +502,26 @@ address += 0x1000; #ifdef CONFIG_POWER4 - extern int boot_text_mapped; - btext_setup_display(width, height, depth, pitch, address); - boot_text_mapped = 0; -#else + { + extern boot_infos_t disp_bi; + unsigned long va, pa, i, offset; + va = 0x90000000; + pa = address & 0xfffff000ul; + offset = address & 0x00000fff; + + for (i=0; i<0x4000; i++) { + make_pte((unsigned long)Hash - KERNELBASE, Hash_size, va, pa, + _PAGE_ACCESSED | _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX); + va += 0x1000; + pa += 0x1000; + } + btext_setup_display(width, height, depth, pitch, 0x90000000 | offset); + disp_bi.dispDeviceBase = (u8 *)address; + } +#else /* CONFIG_POWER4 */ btext_setup_display(width, height, depth, pitch, address); btext_prepare_BAT(); -#endif +#endif /* CONFIG_POWER4 */ #endif /* CONFIG_BOOTX_TEXT */ } @@ -648,72 +729,6 @@ } } -#ifdef CONFIG_POWER4 -/* - * Set up a hash table with a set of entries in it to map the - * first 64MB of RAM. This is used on 64-bit machines since - * some of them don't have BATs. - * We assume the PTE will fit in the primary PTEG. - */ - -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, vsid; - - 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] = vsid | ((va >> 16) & 0xf80) | 1; - pteg[3] = pa | mode; - break; - } - } -} - -extern unsigned long _SDR1; -extern PTE *Hash; -extern unsigned long Hash_size; - -static void __init -prom_alloc_htab(void) -{ - unsigned int hsize; - unsigned long htab; - unsigned int addr; - - /* - * Because of OF bugs we can't use the "claim" client - * interface to allocate memory for the hash table. - * This code is only used on 64-bit PPCs, and the only - * 64-bit PPCs at the moment are RS/6000s, and their - * OF is based at 0xc00000 (the 12M point), so we just - * arbitrarily use the 0x800000 - 0xc00000 region for the - * hash table. - * -- paulus. - */ - hsize = 4 << 20; /* POWER4 has no BATs */ - htab = (8 << 20); - call_prom("claim", 3, 1, htab, hsize, 0); - Hash = (void *)(htab + KERNELBASE); - Hash_size = hsize; - _SDR1 = htab + __ilog2(hsize) - 18; - - /* - * Put in PTEs for the first 64MB of RAM - */ - cacheable_memzero((void *)htab, hsize); - for (addr = 0; addr < 0x4000000; addr += 0x1000) - make_pte(htab, hsize, addr + KERNELBASE, addr, - _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX); - make_pte(htab, hsize, 0x80013000, 0x80013000, - _PAGE_ACCESSED | _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX); -} -#endif /* CONFIG_POWER4 */ - static void __init prom_instantiate_rtas(void) { @@ -836,9 +851,10 @@ * loaded by an OF bootloader which did set a BAT for us. * This breaks OF translate so we force phys to be 0. */ - if (offset == 0) + if (offset == 0) { + prom_print("(already at 0xc0000000) phys=0\n"); phys = 0; - else if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu", + } else if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu", &prom_mmu, sizeof(prom_mmu)) <= 0) { prom_print(" no MMU found\n"); } else if ((int)call_prom_ret("call-method", 4, 4, result, "translate", --- diff/arch/ppc64/Kconfig 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ppc64/Kconfig 2004-02-09 10:39:51.000000000 +0000 @@ -251,54 +251,10 @@ endmenu -source "drivers/base/Kconfig" - -source "drivers/mtd/Kconfig" - -source "drivers/parport/Kconfig" - -source "drivers/pnp/Kconfig" - -source "drivers/block/Kconfig" - -source "drivers/ide/Kconfig" - -source "drivers/scsi/Kconfig" - -source "drivers/md/Kconfig" - -source "drivers/message/fusion/Kconfig" - -source "drivers/ieee1394/Kconfig" - -source "drivers/message/i2o/Kconfig" - -source "net/Kconfig" - -source "drivers/isdn/Kconfig" - -source "drivers/telephony/Kconfig" - -# -# input before char - char/joystick depends on it. As does USB. -# -source "drivers/input/Kconfig" - -source "drivers/char/Kconfig" - -source "drivers/i2c/Kconfig" - -source "drivers/media/Kconfig" +source "drivers/Kconfig" source "fs/Kconfig" -source "drivers/video/Kconfig" - -source "sound/Kconfig" - -source "drivers/usb/Kconfig" - - menu "iSeries device drivers" depends on PPC_ISERIES @@ -401,6 +357,13 @@ debugging info resulting in a larger kernel image. Say Y here only if you plan to use gdb to debug the kernel. If you don't debug the kernel, you can say N. + +config DEBUG_SPINLOCK_SLEEP + bool "Sleep-inside-spinlock checking" + depends on DEBUG_KERNEL + help + If you say Y here, various routines which may sleep will become very + noisy if they are called with a spinlock held. endmenu --- diff/arch/ppc64/kernel/Makefile 2004-02-09 10:36:07.000000000 +0000 +++ source/arch/ppc64/kernel/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -39,6 +39,6 @@ obj-$(CONFIG_SCANLOG) += scanlog.o obj-$(CONFIG_VIOPATH) += viopath.o obj-$(CONFIG_LPARCFG) += lparcfg.o - +obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o CFLAGS_ioctl32.o += -Ifs/ --- diff/arch/ppc64/kernel/head.S 2004-02-09 10:36:08.000000000 +0000 +++ source/arch/ppc64/kernel/head.S 2004-02-09 10:39:51.000000000 +0000 @@ -52,7 +52,7 @@ /* * hcall interface to pSeries LPAR */ -#define HSC .long 0x44000022 +#define HVSC .long 0x44000022 #define H_SET_ASR 0x30 /* @@ -1743,7 +1743,7 @@ cmpwi r3,0x34 /* Pulsar */ bne 98f 97: li r3,H_SET_ASR /* hcall = H_SET_ASR */ - HSC /* Invoking hcall */ + HVSC /* Invoking hcall */ b 99f 98: /* !(rpa hypervisor) || !(star) */ mtasr r4 /* set the stab location */ @@ -1912,7 +1912,7 @@ cmpwi r3,0x34 /* Pulsar */ bne 98f 97: li r3,H_SET_ASR /* hcall = H_SET_ASR */ - HSC /* Invoking hcall */ + HVSC /* Invoking hcall */ b 99f 98: /* !(rpa hypervisor) || !(star) */ mtasr r4 /* set the stab location */ --- diff/arch/ppc64/kernel/iSeries_htab.c 2004-02-09 10:36:08.000000000 +0000 +++ source/arch/ppc64/kernel/iSeries_htab.c 2004-02-09 10:39:51.000000000 +0000 @@ -109,6 +109,12 @@ return -1; } +/* + * The HyperVisor expects the "flags" argument in this form: + * bits 0..59 : reserved + * bit 60 : N + * bits 61..63 : PP2,PP1,PP0 + */ static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, unsigned long va, int large, int local) { @@ -117,7 +123,7 @@ HvCallHpt_get(&hpte, slot); if ((hpte.dw0.dw0.avpn == avpn) && (hpte.dw0.dw0.v)) { - HvCallHpt_setPp(slot, newpp); + HvCallHpt_setPp(slot, (newpp & 0x3) | ((newpp & 0x4) << 1)); return 0; } return -1; --- diff/arch/ppc64/kernel/idle.c 2004-02-09 10:36:08.000000000 +0000 +++ source/arch/ppc64/kernel/idle.c 2004-02-09 10:39:51.000000000 +0000 @@ -161,7 +161,7 @@ struct paca_struct *lpaca = get_paca(), *ppaca; unsigned long start_snooze; - ppaca = &paca[(lpaca->xPacaIndex) ^ 1]; + ppaca = &paca[smp_processor_id() ^ 1]; while (1) { /* Indicate to the HV that we are idle. Now would be --- diff/arch/ppc64/kernel/lparcfg.c 2004-02-09 10:36:08.000000000 +0000 +++ source/arch/ppc64/kernel/lparcfg.c 2004-02-09 10:39:51.000000000 +0000 @@ -134,7 +134,7 @@ memset(buf, 0, size); shared = (int)(lpaca->xLpPacaPtr->xSharedProc); - n += snprintf(buf, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf, LPARCFG_BUFF_SIZE - n, "serial_number=%c%c%c%c%c%c%c\n", e2a(xItExtVpdPanel.mfgID[2]), e2a(xItExtVpdPanel.mfgID[3]), @@ -144,7 +144,7 @@ e2a(xItExtVpdPanel.systemSerial[4]), e2a(xItExtVpdPanel.systemSerial[5])); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "system_type=%c%c%c%c\n", e2a(xItExtVpdPanel.machineType[0]), e2a(xItExtVpdPanel.machineType[1]), @@ -152,23 +152,23 @@ e2a(xItExtVpdPanel.machineType[3])); lp_index = HvLpConfig_getLpIndex(); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "partition_id=%d\n", (int)lp_index); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "system_active_processors=%d\n", (int)HvLpConfig_getSystemPhysicalProcessors()); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "system_potential_processors=%d\n", (int)HvLpConfig_getSystemPhysicalProcessors()); processors = (int)HvLpConfig_getPhysicalProcessors(); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "partition_active_processors=%d\n", processors); max_processors = (int)HvLpConfig_getMaxPhysicalProcessors(); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "partition_potential_processors=%d\n", max_processors); if(shared) { @@ -178,22 +178,22 @@ entitled_capacity = processors * 100; max_entitled_capacity = max_processors * 100; } - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "partition_entitled_capacity=%d\n", entitled_capacity); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "partition_max_entitled_capacity=%d\n", max_entitled_capacity); if(shared) { pool_id = HvLpConfig_getSharedPoolIndex(); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, "pool=%d\n", + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "pool=%d\n", (int)pool_id); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "pool_capacity=%d\n", (int)(HvLpConfig_getNumProcsInSharedPool(pool_id)*100)); } - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "shared_processor_mode=%d\n", shared); return 0; @@ -297,13 +297,13 @@ if(lp_index_ptr) lp_index = *lp_index_ptr; } - n = snprintf(buf, LPARCFG_BUFF_SIZE - n, + n = scnprintf(buf, LPARCFG_BUFF_SIZE - n, "serial_number=%s\n", system_id); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "system_type=%s\n", model); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "partition_id=%d\n", (int)lp_index); rtas_node = find_path_device("/rtas"); @@ -317,74 +317,74 @@ if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { h_get_ppp(&h_entitled,&h_unallocated,&h_aggregation,&h_resource); #ifdef DEBUG - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "R4=0x%lx\n", h_entitled); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "R5=0x%lx\n", h_unallocated); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "R6=0x%lx\n", h_aggregation); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "R7=0x%lx\n", h_resource); #endif /* DEBUG */ } if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { system_potential_processors = get_splpar_potential_characteristics(); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, - "system_active_processors=%d\n", + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, + "system_active_processors=%ld\n", (h_resource >> 2*8) & 0xffff); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "system_potential_processors=%d\n", system_potential_processors); } else { system_potential_processors = system_active_processors; - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "system_active_processors=%d\n", system_active_processors); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "system_potential_processors=%d\n", system_potential_processors); } processors = systemcfg->processorCount; - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "partition_active_processors=%d\n", processors); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "partition_potential_processors=%d\n", system_active_processors); /* max_entitled_capacity will come out of get_splpar_potential_characteristics() when that function is complete */ max_entitled_capacity = system_active_processors * 100; if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "partition_entitled_capacity=%ld\n", h_entitled); } else { - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "partition_entitled_capacity=%d\n", system_active_processors*100); } - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "partition_max_entitled_capacity=%d\n", max_entitled_capacity); shared = 0; - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "shared_processor_mode=%d\n", shared); if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, - "pool=%d\n", (h_aggregation >> 0*8)&0xffff); + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, + "pool=%ld\n", (h_aggregation >> 0*8)&0xffff); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, - "pool_capacity=%d\n", (h_resource >> 3*8) &0xffff); + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, + "pool_capacity=%ld\n", (h_resource >> 3*8) &0xffff); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, - "group=%d\n", (h_aggregation >> 2*8)&0xffff); + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, + "group=%ld\n", (h_aggregation >> 2*8)&0xffff); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, - "capped=%d\n", (h_resource >> 6*8)&0x40); + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, + "capped=%ld\n", (h_resource >> 6*8)&0x40); - n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, + n += scnprintf(buf+n, LPARCFG_BUFF_SIZE - n, "capacity_weight=%d\n", (int)(h_resource>>5*8)&0xFF); } return 0; --- diff/arch/ppc64/kernel/pSeries_hvCall.S 2004-02-09 10:36:08.000000000 +0000 +++ source/arch/ppc64/kernel/pSeries_hvCall.S 2004-02-09 10:39:51.000000000 +0000 @@ -22,7 +22,7 @@ /* * hcall interface to pSeries LPAR */ -#define HSC .long 0x44000022 +#define HVSC .long 0x44000022 /* long plpar_hcall(unsigned long opcode, R3 unsigned long arg1, R4 @@ -44,7 +44,7 @@ std r9,-16(r1) std r10,-24(r1) - HSC /* invoke the hypervisor */ + HVSC /* invoke the hypervisor */ ld r10,-8(r1) /* Fetch r4-r7 ret args. */ std r4,0(r10) @@ -63,7 +63,7 @@ _GLOBAL(plpar_hcall_norets) mfcr r0 std r0,-8(r1) - HSC /* invoke the hypervisor */ + HVSC /* invoke the hypervisor */ ld r0,-8(r1) mtcrf 0xff,r0 blr /* return r3 = status */ @@ -94,7 +94,7 @@ std r12,-8(r1) /* Save out ptr */ - HSC /* invoke the hypervisor */ + HVSC /* invoke the hypervisor */ ld r10,-8(r1) /* Fetch r4 ret arg */ std r4,0(r10) @@ -126,7 +126,7 @@ std r10,16(r1) std r14,8(r1) - HSC /* invoke the hypervisor */ + HVSC /* invoke the hypervisor */ ld r14,32(r1) /* Fetch r4-r7 ret args. */ std r4,0(r14) --- diff/arch/ppc64/kernel/pSeries_lpar.c 2004-02-09 10:36:08.000000000 +0000 +++ source/arch/ppc64/kernel/pSeries_lpar.c 2004-02-09 10:39:51.000000000 +0000 @@ -313,69 +313,6 @@ } } -int hvc_get_chars(int index, char *buf, int count) -{ - unsigned long got; - - if (plpar_hcall(H_GET_TERM_CHAR, index, 0, 0, 0, &got, - (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) { - /* - * Work around a HV bug where it gives us a null - * after every \r. -- paulus - */ - if (got > 0) { - int i; - for (i = 1; i < got; ++i) { - if (buf[i] == 0 && buf[i-1] == '\r') { - --got; - if (i < got) - memmove(&buf[i], &buf[i+1], - got - i); - } - } - } - return got; - } - return 0; -} - -int hvc_put_chars(int index, const char *buf, int count) -{ - unsigned long *lbuf = (unsigned long *) buf; - long ret; - - ret = plpar_hcall_norets(H_PUT_TERM_CHAR, index, count, lbuf[0], - lbuf[1]); - if (ret == H_Success) - return count; - if (ret == H_Busy) - return 0; - return -1; -} - -/* return the number of client vterms present */ -/* XXX this requires an interface change to handle multiple discontiguous - * vterms */ -int hvc_count(int *start_termno) -{ - struct device_node *vty; - int num_found = 0; - - /* consider only the first vty node. - * we should _always_ be able to find one. */ - vty = of_find_node_by_name(NULL, "vty"); - if (vty && device_is_compatible(vty, "hvterm1")) { - u32 *termno = (u32 *)get_property(vty, "reg", 0); - - if (termno && start_termno) - *start_termno = *termno; - num_found = 1; - of_node_put(vty); - } - - return num_found; -} - long pSeries_lpar_hpte_insert(unsigned long hpte_group, unsigned long va, unsigned long prpn, int secondary, unsigned long hpteflags, --- diff/arch/ppc64/kernel/pSeries_pci.c 2004-02-09 10:36:08.000000000 +0000 +++ source/arch/ppc64/kernel/pSeries_pci.c 2004-02-09 10:39:51.000000000 +0000 @@ -721,3 +721,29 @@ } return NULL; } + +/* + * ppc64 can have multifunction devices that do not respond to function 0. + * In this case we must scan all functions. + */ +int +pcibios_scan_all_fns(struct pci_bus *bus, int devfn) +{ + struct device_node *busdn, *dn; + + if (bus->self) + busdn = pci_device_to_OF_node(bus->self); + else + busdn = bus->sysdata; /* must be a phb */ + + /* + * Check to see if there is any of the 8 functions are in the + * device tree. If they are then we need to scan all the + * functions of this slot. + */ + for (dn = busdn->child; dn; dn = dn->sibling) + if ((dn->devfn >> 3) == (devfn >> 3)) + return 1; + + return 0; +} --- diff/arch/ppc64/kernel/proc_ppc64.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/ppc64/kernel/proc_ppc64.c 2004-02-09 10:39:51.000000000 +0000 @@ -268,12 +268,10 @@ static int do_remove_node(char *buf) { struct device_node *node; - int rv = 0; + int rv = -ENODEV; if ((node = of_find_node_by_path(buf))) - of_remove_node(node); - else - rv = -ENODEV; + rv = of_remove_node(node); of_node_put(node); return rv; --- diff/arch/ppc64/kernel/prom.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/ppc64/kernel/prom.c 2004-02-09 10:39:51.000000000 +0000 @@ -2507,29 +2507,48 @@ /* * Remove an OF device node from the system. + * Caller should have already "gotten" np. */ int of_remove_node(struct device_node *np) { struct device_node *parent, *child; parent = of_get_parent(np); - child = of_get_next_child(np, NULL); - if (child && !child->child && !child->sibling) { - /* For now, we will allow removal of a - * node with one and only one child, so - * that we can support removing a slot with - * an IOA in it. More general support for - * subtree removal to be implemented later, if - * necessary. - */ - of_remove_node(child); - } - else if (child) { - of_node_put(child); - of_node_put(parent); + + if (!parent) return -EINVAL; + + /* Make sure we are not recursively removing + * more than one level of nodes. We need to + * allow this so we can remove a slot containing + * an IOA. + */ + for (child = of_get_next_child(np, NULL); + child != NULL; + child = of_get_next_child(np, child)) { + struct device_node *grandchild; + + if ((grandchild = of_get_next_child(child, NULL))) { + /* Too deep */ + of_node_put(grandchild); + of_node_put(child); + return -EBUSY; + } + } + + /* Now that we're reasonably sure that we won't + * overflow our stack, remove any children of np. + */ + for (child = of_get_next_child(np, NULL); + child != NULL; + child = of_get_next_child(np, child)) { + int rc; + + if ((rc = of_remove_node(child))) { + of_node_put(child); + return rc; + } } - of_node_put(child); write_lock(&devtree_lock); OF_MARK_STALE(np); @@ -2545,8 +2564,8 @@ prev->allnext = np->allnext; } - if (np->parent->child == np) - np->parent->child = np->sibling; + if (parent->child == np) + parent->child = np->sibling; else { struct device_node *prevsib; for (prevsib = np->parent->child; --- diff/arch/ppc64/kernel/rtas-proc.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/ppc64/kernel/rtas-proc.c 2004-02-09 10:39:51.000000000 +0000 @@ -285,13 +285,13 @@ size_t count, loff_t *ppos) { char stkbuf[40]; /* its small, its on stack */ - int n; + int n, sn; if (power_on_time == 0) - n = snprintf(stkbuf, 40, "Power on time not set\n"); + n = scnprintf(stkbuf,sizeof(stkbuf),"Power on time not set\n"); else - n = snprintf(stkbuf, 40, "%lu\n", power_on_time); + n = scnprintf(stkbuf,sizeof(stkbuf),"%lu\n",power_on_time); - int sn = strlen (stkbuf) +1; + sn = strlen (stkbuf) +1; if (*ppos >= sn) return 0; if (n > sn - *ppos) @@ -331,18 +331,19 @@ static ssize_t ppc_rtas_progress_read(struct file * file, char * buf, size_t count, loff_t *ppos) { - int n = 0; + int sn, n = 0; + char *tmpbuf; if (progress_led == NULL) return 0; - char * tmpbuf = kmalloc (MAX_LINELENGTH, GFP_KERNEL); + tmpbuf = kmalloc (MAX_LINELENGTH, GFP_KERNEL); if (!tmpbuf) { printk(KERN_ERR "error: kmalloc failed\n"); return -ENOMEM; } n = sprintf (tmpbuf, "%s\n", progress_led); - int sn = strlen (tmpbuf) +1; + sn = strlen (tmpbuf) +1; if (*ppos >= sn) { kfree (tmpbuf); return 0; @@ -398,25 +399,25 @@ { unsigned int year, mon, day, hour, min, sec; unsigned long *ret = kmalloc(4*8, GFP_KERNEL); - int n, error; + int n, sn, error; + char stkbuf[40]; /* its small, its on stack */ error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); year = ret[0]; mon = ret[1]; day = ret[2]; hour = ret[3]; min = ret[4]; sec = ret[5]; - char stkbuf[40]; /* its small, its on stack */ - if (error != 0){ printk(KERN_WARNING "error: reading the clock returned: %s\n", ppc_rtas_process_error(error)); - n = snprintf (stkbuf, 40, "0"); + n = scnprintf (stkbuf, sizeof(stkbuf), "0"); } else { - n = snprintf (stkbuf, 40, "%lu\n", mktime(year, mon, day, hour, min, sec)); + n = scnprintf (stkbuf, sizeof(stkbuf), "%lu\n", + mktime(year, mon, day, hour, min, sec)); } kfree(ret); - int sn = strlen (stkbuf) +1; + sn = strlen (stkbuf) +1; if (*ppos >= sn) return 0; if (n > sn - *ppos) @@ -819,7 +820,7 @@ n += check_location_string(ret, buffer + n); n += sprintf ( buffer+n, " "); /* see how many characters we have printed */ - snprintf ( t, 50, "%s ", ret); + scnprintf(t, sizeof(t), "%s ", ret); pos += strlen(t); if (pos >= llen) pos=0; @@ -860,11 +861,12 @@ static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf, size_t count, loff_t *ppos) { - int n; + int n, sn; char stkbuf[40]; /* its small, its on stack */ - n = snprintf(stkbuf, 40, "%lu\n", rtas_tone_frequency); - int sn = strlen (stkbuf) +1; + n = scnprintf(stkbuf, 40, "%lu\n", rtas_tone_frequency); + + sn = strlen (stkbuf) +1; if (*ppos >= sn) return 0; if (n > sn - *ppos) @@ -913,11 +915,12 @@ static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf, size_t count, loff_t *ppos) { - int n; + int n, sn; char stkbuf[40]; /* its small, its on stack */ - n = snprintf(stkbuf, 40, "%lu\n", rtas_tone_volume); - int sn = strlen (stkbuf) +1; + n = scnprintf(stkbuf, 40, "%lu\n", rtas_tone_volume); + + sn = strlen (stkbuf) +1; if (*ppos >= sn) return 0; if (n > sn - *ppos) --- diff/arch/ppc64/kernel/setup.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/ppc64/kernel/setup.c 2004-02-09 10:39:51.000000000 +0000 @@ -283,6 +283,10 @@ unsigned long ppc_proc_freq; unsigned long ppc_tb_freq; +#ifdef CONFIG_SMP +DEFINE_PER_CPU(unsigned int, pvr); +#endif + static int show_cpuinfo(struct seq_file *m, void *v) { unsigned long cpu_id = (unsigned long)v - 1; @@ -302,7 +306,7 @@ return 0; #ifdef CONFIG_SMP - pvr = paca[cpu_id].pvr; + pvr = per_cpu(pvr, cpu_id); #else pvr = _get_PVR(); #endif --- diff/arch/ppc64/kernel/smp.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/ppc64/kernel/smp.c 2004-02-09 10:39:51.000000000 +0000 @@ -575,9 +575,11 @@ struct thread_info *current_set[NR_CPUS]; +DECLARE_PER_CPU(unsigned int, pvr); + static void __devinit smp_store_cpu_info(int id) { - paca[id].pvr = _get_PVR(); + per_cpu(pvr, id) = _get_PVR(); } void __init smp_prepare_cpus(unsigned int max_cpus) --- diff/arch/ppc64/kernel/stab.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/ppc64/kernel/stab.c 2004-02-09 10:39:51.000000000 +0000 @@ -141,8 +141,7 @@ return (global_entry | (castout_entry & 0x7)); } -static inline void __ste_allocate(unsigned long esid, unsigned long vsid, - mm_context_t context) +static inline void __ste_allocate(unsigned long esid, unsigned long vsid) { unsigned char stab_entry; unsigned long *offset; @@ -185,7 +184,7 @@ } esid = GET_ESID(ea); - __ste_allocate(esid, vsid, context); + __ste_allocate(esid, vsid); /* Order update */ asm volatile("sync":::"memory"); @@ -215,7 +214,7 @@ if (!IS_VALID_EA(pc) || (REGION_ID(pc) >= KERNEL_REGION_ID)) return; vsid = get_vsid(mm->context, pc); - __ste_allocate(pc_esid, vsid, mm->context); + __ste_allocate(pc_esid, vsid); if (pc_esid == stack_esid) return; @@ -223,7 +222,7 @@ if (!IS_VALID_EA(stack) || (REGION_ID(stack) >= KERNEL_REGION_ID)) return; vsid = get_vsid(mm->context, stack); - __ste_allocate(stack_esid, vsid, mm->context); + __ste_allocate(stack_esid, vsid); if (pc_esid == unmapped_base_esid || stack_esid == unmapped_base_esid) return; @@ -232,7 +231,7 @@ (REGION_ID(unmapped_base) >= KERNEL_REGION_ID)) return; vsid = get_vsid(mm->context, unmapped_base); - __ste_allocate(unmapped_base_esid, vsid, mm->context); + __ste_allocate(unmapped_base_esid, vsid); /* Order update */ asm volatile("sync" : : : "memory"); --- diff/arch/ppc64/kernel/time.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/ppc64/kernel/time.c 2004-02-09 10:39:51.000000000 +0000 @@ -267,7 +267,7 @@ int next_dec; unsigned long cur_tb; struct paca_struct *lpaca = get_paca(); - unsigned long cpu = lpaca->xPacaIndex; + unsigned long cpu = smp_processor_id(); irq_enter(); --- diff/arch/ppc64/kernel/vio.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/ppc64/kernel/vio.c 2004-02-09 10:39:51.000000000 +0000 @@ -4,6 +4,7 @@ * Copyright (c) 2003 IBM Corp. * Dave Engebretsen engebret@us.ibm.com * Santiago Leon santil@us.ibm.com + * Hollis Blanchard * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -16,14 +17,16 @@ #include #include #include +#include +#include #include #include #include #include #include #include -#include -#include "open_pic.h" /* temporary, until we merge large irq support */ + +#define DBGENTER() pr_debug("%s entered\n", __FUNCTION__) extern struct TceTable *build_tce_table(struct TceTable *tbl); @@ -32,83 +35,74 @@ extern void tce_free(struct TceTable *tbl, dma_addr_t dma_addr, unsigned order, unsigned num_pages); +static int vio_num_address_cells; +static struct vio_dev *vio_bus_device; /* fake "parent" device */ -static struct vio_bus vio_bus; -static LIST_HEAD(registered_vio_drivers); -int vio_num_address_cells; -EXPORT_SYMBOL(vio_num_address_cells); - -/* TODO: - * really fit into driver model (see include/linux/device.h) - * locking around list accesses - */ +/* convert from struct device to struct vio_dev and pass to driver. + * dev->driver has already been set by generic code because vio_bus_match + * succeeded. */ +static int vio_bus_probe(struct device *dev) +{ + struct vio_dev *viodev = to_vio_dev(dev); + struct vio_driver *viodrv = to_vio_driver(dev->driver); + const struct vio_device_id *id; + int error = -ENODEV; + + DBGENTER(); + + if (!viodrv->probe) + return error; + + id = vio_match_device(viodrv->id_table, viodev); + if (id) { + error = viodrv->probe(viodev, id); + } + + return error; +} + +/* convert from struct device to struct vio_dev and pass to driver. */ +static int vio_bus_remove(struct device *dev) +{ + struct vio_dev *viodev = to_vio_dev(dev); + struct vio_driver *viodrv = to_vio_driver(dev->driver); + + DBGENTER(); + + if (viodrv->remove) { + return viodrv->remove(viodev); + } + + /* driver can't remove */ + return 1; +} /** * vio_register_driver: - Register a new vio driver * @drv: The vio_driver structure to be registered. - * - * Adds the driver structure to the list of registered drivers - * Returns the number of vio devices which were claimed by the driver - * during registration. The driver remains registered even if the - * return value is zero. */ -int vio_register_driver(struct vio_driver *drv) +int vio_register_driver(struct vio_driver *viodrv) { - int count = 0; - struct vio_dev *dev; - - printk(KERN_DEBUG "%s: driver %s/%s registering\n", __FUNCTION__, - drv->id_table[0].type, drv->id_table[0].type); - - /* find matching devices not already claimed by other drivers and pass - * them to probe() */ - list_for_each_entry(dev, &vio_bus.devices, devices_list) { - const struct vio_device_id* id; - - if (dev->driver) - continue; /* this device is already owned */ - - id = vio_match_device(drv->id_table, dev); - if (drv && id) { - if (0 == drv->probe(dev, id)) { - printk(KERN_DEBUG " took device %p\n", dev); - dev->driver = drv; - count++; - } - } - } + printk(KERN_DEBUG "%s: driver %s registering\n", __FUNCTION__, + viodrv->name); - list_add_tail(&drv->node, ®istered_vio_drivers); + /* fill in 'struct driver' fields */ + viodrv->driver.name = viodrv->name; + viodrv->driver.bus = &vio_bus_type; + viodrv->driver.probe = vio_bus_probe; + viodrv->driver.remove = vio_bus_remove; - return count; + return driver_register(&viodrv->driver); } EXPORT_SYMBOL(vio_register_driver); /** * vio_unregister_driver - Remove registration of vio driver. * @driver: The vio_driver struct to be removed form registration - * - * Searches for devices that are assigned to the driver and calls - * driver->remove() for each one. Removes the driver from the list - * of registered drivers. Returns the number of devices that were - * assigned to that driver. */ -int vio_unregister_driver(struct vio_driver *driver) +void vio_unregister_driver(struct vio_driver *viodrv) { - struct vio_dev *dev; - int devices_found = 0; - - list_for_each_entry(dev, &vio_bus.devices, devices_list) { - if (dev->driver == driver) { - driver->remove(dev); - dev->driver = NULL; - devices_found++; - } - } - - list_del(&driver->node); - - return devices_found; + driver_unregister(&viodrv->driver); } EXPORT_SYMBOL(vio_unregister_driver); @@ -121,9 +115,11 @@ * system is in its list of supported devices. Returns the matching * vio_device_id structure or NULL if there is no match. */ -const struct vio_device_id * -vio_match_device(const struct vio_device_id *ids, const struct vio_dev *dev) +const struct vio_device_id * vio_match_device(const struct vio_device_id *ids, + const struct vio_dev *dev) { + DBGENTER(); + while (ids->type) { if ((strncmp(dev->archdata->type, ids->type, strlen(ids->type)) == 0) && device_is_compatible((struct device_node*)dev->archdata, ids->compat)) @@ -136,18 +132,33 @@ /** * vio_bus_init: - Initialize the virtual IO bus */ -int __init -vio_bus_init(void) +static int __init vio_bus_init(void) { - struct device_node *node_vroot, *node_vdev; + struct device_node *node_vroot, *of_node; + int err; - INIT_LIST_HEAD(&vio_bus.devices); + err = bus_register(&vio_bus_type); + if (err) { + printk(KERN_ERR "failed to register VIO bus\n"); + return err; + } + + /* the fake parent of all vio devices, just to give us a nice directory */ + vio_bus_device = kmalloc(sizeof(struct vio_dev), GFP_KERNEL); + if (!vio_bus_device) { + return 1; + } + memset(vio_bus_device, 0, sizeof(struct vio_dev)); + strcpy(vio_bus_device->dev.bus_id, "vdevice"); + + err = device_register(&vio_bus_device->dev); + if (err) { + printk(KERN_WARNING "%s: device_register returned %i\n", __FUNCTION__, + err); + kfree(vio_bus_device); + return err; + } - /* - * Create device node entries for each virtual device - * identified in the device tree. - * Functionally takes the place of pci_scan_bus - */ node_vroot = find_devices("vdevice"); if ((node_vroot == NULL) || (node_vroot->child == NULL)) { printk(KERN_INFO "VIO: missing or empty /vdevice node; no virtual IO" @@ -157,12 +168,16 @@ vio_num_address_cells = prom_n_addr_cells(node_vroot->child); - for (node_vdev = node_vroot->child; - node_vdev != NULL; - node_vdev = node_vdev->sibling) { - printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, node_vdev); + /* + * Create struct vio_devices for each virtual device in the device tree. + * Drivers will associate with them later. + */ + for (of_node = node_vroot->child; + of_node != NULL; + of_node = of_node->sibling) { + printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node); - vio_register_device(node_vdev); + vio_register_device(of_node); } return 0; @@ -171,98 +186,91 @@ __initcall(vio_bus_init); -/** - * vio_probe_device - attach dev to appropriate driver - * @dev: device to find a driver for - * - * Walks the list of registered VIO drivers looking for one to take this - * device. - * - * Returns a pointer to the matched driver or NULL if driver is not - * found. - */ -struct vio_driver * __devinit vio_probe_device(struct vio_dev* dev) +/* vio_dev refcount hit 0 */ +static void __devinit vio_dev_release(struct device *dev) { - struct vio_driver *driver; - - list_for_each_entry(driver, ®istered_vio_drivers, node) { - const struct vio_device_id* id; + struct vio_dev *viodev = to_vio_dev(dev); - id = vio_match_device(driver->id_table, dev); - if (id && (0 < driver->probe(dev, id))) { - printk(KERN_DEBUG "%s: driver %s/%s took device %p\n", - __FUNCTION__, id->type, id->compat, dev); - dev->driver = driver; - return driver; - } - } + DBGENTER(); - printk(KERN_DEBUG "%s: device %p found no driver\n", __FUNCTION__, dev); - return NULL; + /* XXX free TCE table */ + of_node_put(viodev->archdata); + kfree(viodev); } /** * vio_register_device: - Register a new vio device. - * @archdata: The OF node for this device. + * @of_node: The OF node for this device. * * Creates and initializes a vio_dev structure from the data in - * node_vdev (archdata) and adds it to the list of virtual devices. + * of_node (archdata) and adds it to the list of virtual devices. * Returns a pointer to the created vio_dev or NULL if node has * NULL device_type or compatible fields. */ -struct vio_dev * __devinit vio_register_device(struct device_node *node_vdev) +struct vio_dev * __devinit vio_register_device(struct device_node *of_node) { - struct vio_dev *dev; + struct vio_dev *viodev; unsigned int *unit_address; unsigned int *irq_p; - /* guarantee all vio_devs have 'device_type' field*/ - if ((NULL == node_vdev->type)) { + DBGENTER(); + + /* we need the 'device_type' property, in order to match with drivers */ + if ((NULL == of_node->type)) { printk(KERN_WARNING "%s: node %s missing 'device_type'\n", __FUNCTION__, - node_vdev->name ? node_vdev->name : ""); + of_node->name ? of_node->name : ""); return NULL; } - unit_address = (unsigned int *)get_property(node_vdev, "reg", NULL); + unit_address = (unsigned int *)get_property(of_node, "reg", NULL); if (!unit_address) { printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__, - node_vdev->name ? node_vdev->name : ""); + of_node->name ? of_node->name : ""); return NULL; } /* allocate a vio_dev for this node */ - dev = kmalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) + viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL); + if (!viodev) { return NULL; - memset(dev, 0, sizeof(*dev)); - - dev->archdata = (void*)of_node_get(node_vdev); - dev->bus = &vio_bus; - dev->unit_address = *unit_address; - dev->tce_table = vio_build_tce_table(dev); - - irq_p = (unsigned int *) get_property(node_vdev, "interrupts", 0); - if(irq_p) { - dev->irq = openpic_to_irq(virt_irq_create_mapping(*irq_p)); - } else { - dev->irq = (unsigned int) -1; } + memset(viodev, 0, sizeof(struct vio_dev)); - list_add_tail(&dev->devices_list, &vio_bus.devices); - - vio_probe_device(dev); /* finally, assign it to a driver */ + viodev->archdata = (void *)of_node_get(of_node); + viodev->unit_address = *unit_address; + viodev->tce_table = vio_build_tce_table(viodev); + + viodev->irq = (unsigned int) -1; + irq_p = (unsigned int *)get_property(of_node, "interrupts", 0); + if (irq_p) { + viodev->irq = irq_offset_up(*irq_p); + } + + /* init generic 'struct device' fields: */ + viodev->dev.parent = &vio_bus_device->dev; + viodev->dev.bus = &vio_bus_type; + snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s@%lx", + of_node->name, viodev->unit_address); + viodev->dev.release = vio_dev_release; + + /* register with generic device framework */ + if (device_register(&viodev->dev)) { + printk(KERN_ERR "%s: failed to register device %s\n", __FUNCTION__, + viodev->dev.bus_id); + /* XXX free TCE table */ + kfree(viodev); + return NULL; + } - return dev; + return viodev; } EXPORT_SYMBOL(vio_register_device); -int __devinit vio_unregister_device(struct vio_dev *dev) +void __devinit vio_unregister_device(struct vio_dev *viodev) { - list_del(&dev->devices_list); - of_node_put(dev->archdata); - - return 0; + DBGENTER(); + device_unregister(&viodev->dev); } EXPORT_SYMBOL(vio_unregister_device); @@ -532,5 +540,29 @@ } EXPORT_SYMBOL(vio_free_consistent); +static int vio_bus_match(struct device *dev, struct device_driver *drv) +{ + const struct vio_dev *vio_dev = to_vio_dev(dev); + struct vio_driver *vio_drv = to_vio_driver(drv); + const struct vio_device_id *ids = vio_drv->id_table; + const struct vio_device_id *found_id; + + DBGENTER(); + + if (!ids) + return 0; + + found_id = vio_match_device(ids, vio_dev); + if (found_id) + return 1; + + return 0; +} + +struct bus_type vio_bus_type = { + .name = "vio", + .match = vio_bus_match, +}; + EXPORT_SYMBOL(plpar_hcall_norets); EXPORT_SYMBOL(plpar_hcall_8arg_2ret); --- diff/arch/ppc64/mm/numa.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/ppc64/mm/numa.c 2004-02-09 10:39:51.000000000 +0000 @@ -273,8 +273,8 @@ physbase = start_paddr; } - if (size > end_paddr - start_paddr) - size = end_paddr - start_paddr; + if (size > end_paddr - physbase) + size = end_paddr - physbase; dbg("free_bootmem %lx %lx\n", physbase, size); free_bootmem_node(NODE_DATA(nid), physbase, @@ -294,8 +294,8 @@ physbase = start_paddr; } - if (size > end_paddr - start_paddr) - size = end_paddr - start_paddr; + if (size > end_paddr - physbase) + size = end_paddr - physbase; dbg("reserve_bootmem %lx %lx\n", physbase, size); --- diff/arch/ppc64/xmon/start.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/ppc64/xmon/start.c 2004-02-09 10:39:51.000000000 +0000 @@ -41,7 +41,7 @@ static struct sysrq_key_op sysrq_xmon_op = { .handler = sysrq_handle_xmon, - .help_msg = "xmon", + .help_msg = "Xmon", .action_msg = "Entering xmon\n", }; --- diff/arch/ppc64/xmon/xmon.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/ppc64/xmon/xmon.c 2004-02-09 10:39:51.000000000 +0000 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -37,7 +38,7 @@ #define skipbl xmon_skipbl #ifdef CONFIG_SMP -volatile unsigned long cpus_in_xmon = 0; +volatile cpumask_t cpus_in_xmon = CPU_MASK_NONE; static unsigned long got_xmon = 0; static volatile int take_xmon = -1; static volatile int leaving_xmon = 0; @@ -288,17 +289,18 @@ leaving_xmon = 0; /* possible race condition here if a CPU is held up and gets * here while we are exiting */ - if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon)) { + if (cpu_test_and_set(smp_processor_id(), cpus_in_xmon)) { /* xmon probably caused an exception itself */ printf("We are already in xmon\n"); for (;;) - ; + cpu_relax(); } while (test_and_set_bit(0, &got_xmon)) { if (take_xmon == smp_processor_id()) { take_xmon = -1; break; } + cpu_relax(); } /* * XXX: breakpoints are removed while any cpu is in xmon @@ -325,7 +327,7 @@ leaving_xmon = 1; if (cmd != 's') clear_bit(0, &got_xmon); - clear_bit(smp_processor_id(), &cpus_in_xmon); + cpu_clear(smp_processor_id(), cpus_in_xmon); #endif /* CONFIG_SMP */ set_msrd(msr); /* restore interrupt enable */ } @@ -602,6 +604,7 @@ printf(" (type ? for help)\n"); break; } + cpu_relax(); } } @@ -638,7 +641,7 @@ /* print cpus waiting or in xmon */ printf("cpus stopped:"); for (cpu = 0; cpu < NR_CPUS; ++cpu) { - if (test_bit(cpu, &cpus_in_xmon)) { + if (cpu_isset(cpu, cpus_in_xmon)) { printf(" %x", cpu); if (cpu == smp_processor_id()) printf("*", cpu); @@ -664,6 +667,7 @@ take_xmon = -1; break; } + cpu_relax(); } } #endif /* CONFIG_SMP */ --- diff/arch/s390/kernel/compat_linux.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/s390/kernel/compat_linux.c 2004-02-09 10:39:51.000000000 +0000 @@ -190,40 +190,82 @@ return sys_setfsgid((gid_t)gid); } +static int groups16_to_user(u16 *grouplist, struct group_info *group_info) +{ + int i; + u16 group; + + for (i = 0; i < group_info->ngroups; i++) { + group = (u16)GROUP_AT(group_info, i); + if (put_user(group, grouplist+i)) + return -EFAULT; + } + + return 0; +} + +static int groups16_from_user(struct group_info *group_info, u16 *grouplist) +{ + int i; + u16 group; + + for (i = 0; i < group_info->ngroups; i++) { + if (get_user(group, grouplist+i)) + return -EFAULT; + GROUP_AT(group_info, i) = (gid_t)group; + } + + return 0; +} + asmlinkage long sys32_getgroups16(int gidsetsize, u16 *grouplist) { - u16 groups[NGROUPS]; - int i,j; + int i; if (gidsetsize < 0) return -EINVAL; - i = current->ngroups; + + get_group_info(current->group_info); + i = current->group_info->ngroups; if (gidsetsize) { - if (i > gidsetsize) - return -EINVAL; - for(j=0;jgroups[j]; - if (copy_to_user(grouplist, groups, sizeof(u16)*i)) - return -EFAULT; + if (i > gidsetsize) { + i = -EINVAL; + goto out; + } + if (groups16_to_user(grouplist, current->group_info)) + i = -EFAULT; + goto out; + } } +out: + put_group_info(current->group_info); return i; } asmlinkage long sys32_setgroups16(int gidsetsize, u16 *grouplist) { - u16 groups[NGROUPS]; - int i; + struct group_info *group_info; + int retval; if (!capable(CAP_SETGID)) return -EPERM; - if ((unsigned) gidsetsize > NGROUPS) + if ((unsigned)gidsetsize > NGROUPS_MAX) return -EINVAL; - if (copy_from_user(groups, grouplist, gidsetsize * sizeof(u16))) - return -EFAULT; - for (i = 0 ; i < gidsetsize ; i++) - current->groups[i] = (gid_t)groups[i]; - current->ngroups = gidsetsize; - return 0; + + group_info = groups_alloc(gidsetsize); + if (!group_info) + return -ENOMEM; + retval = groups16_from_user(group_info, grouplist); + if (retval) { + put_group_info(group_info); + return retval; + } + + retval = set_current_groups(group_info); + if (retval) + put_group_info(group_info); + + return retval; } asmlinkage long sys32_getuid16(void) --- diff/arch/sparc/prom/printf.c 2002-10-16 04:27:16.000000000 +0100 +++ source/arch/sparc/prom/printf.c 2004-02-09 10:39:51.000000000 +0000 @@ -39,7 +39,7 @@ int i; va_start(args, fmt); - i = vsnprintf(ppbuf, sizeof(ppbuf), fmt, args); + i = vscnprintf(ppbuf, sizeof(ppbuf), fmt, args); va_end(args); prom_write(ppbuf, i); --- diff/arch/sparc64/Kconfig 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/sparc64/Kconfig 2004-02-09 10:39:51.000000000 +0000 @@ -731,12 +731,19 @@ depends on DEBUG_KERNEL bool "Debug BOOTMEM initialization" +config LOCKMETER + bool "Kernel lock metering" + depends on SMP && !PREEMPT + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + # We have a custom atomic_dec_and_lock() implementation but it's not # compatible with spinlock debugging so we need to fall back on # the generic version in that case. config HAVE_DEC_LOCK bool - depends on SMP && !DEBUG_SPINLOCK + depends on SMP && !DEBUG_SPINLOCK && !LOCKMETER default y config MCOUNT --- diff/arch/sparc64/kernel/head.S 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/sparc64/kernel/head.S 2004-02-09 10:39:51.000000000 +0000 @@ -61,7 +61,7 @@ * 0x0202 : Supports kernel params string * 0x0201 : Supports reboot_command */ - .half 0x0300 /* HdrS version */ + .half 0x0300 /* HdrS version */ root_flags: .half 1 @@ -159,6 +159,21 @@ blu,pt %xcc, 1b add %l0, (1 << 3), %l0 + /* Search the small TLB. OBP never maps us like that but + * newer SILO can. + */ + clr %l0 + +1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1 + membar #Sync + andn %g1, %l2, %g1 + cmp %g1, %g2 + be,pn %xcc, cheetah_got_tlbentry + nop + cmp %l0, (15 << 3) + blu,pt %xcc, 1b + add %l0, (1 << 3), %l0 + /* BUG() if we get here... */ ta 0x5 @@ -167,7 +182,8 @@ ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1 membar #Sync and %g1, %g3, %g1 - sub %g1, %g2, %g1 + set 0x5fff, %l0 + andn %g1, %l0, %g1 or %g5, %g1, %g5 /* Clear out any KERNBASE area entries. */ --- diff/arch/sparc64/kernel/sys_sparc32.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/sparc64/kernel/sys_sparc32.c 2004-02-09 10:39:51.000000000 +0000 @@ -179,40 +179,82 @@ return sys_setfsgid((gid_t)gid); } +static int groups16_to_user(u16 *grouplist, struct group_info *group_info) +{ + int i; + u16 group; + + for (i = 0; i < group_info->ngroups; i++) { + group = (u16)GROUP_AT(group_info, i); + if (put_user(group, grouplist+i)) + return -EFAULT; + } + + return 0; +} + +static int groups16_from_user(struct group_info *group_info, u16 *grouplist) +{ + int i; + u16 group; + + for (i = 0; i < group_info->ngroups; i++) { + if (get_user(group, grouplist+i)) + return -EFAULT; + GROUP_AT(group_info, i) = (gid_t)group; + } + + return 0; +} + asmlinkage long sys32_getgroups16(int gidsetsize, u16 *grouplist) { - u16 groups[NGROUPS]; - int i,j; + int i; if (gidsetsize < 0) return -EINVAL; - i = current->ngroups; + + get_group_info(current->group_info); + i = current->group_info->ngroups; if (gidsetsize) { - if (i > gidsetsize) - return -EINVAL; - for(j=0;jgroups[j]; - if (copy_to_user(grouplist, groups, sizeof(u16)*i)) - return -EFAULT; + if (i > gidsetsize) { + i = -EINVAL; + goto out; + } + if (groups16_to_user(grouplist, current->group_info)) { + i = -EFAULT; + goto out; + } } +out: + put_group_info(current->group_info); return i; } asmlinkage long sys32_setgroups16(int gidsetsize, u16 *grouplist) { - u16 groups[NGROUPS]; - int i; + struct group_info *group_info; + int retval; if (!capable(CAP_SETGID)) return -EPERM; - if ((unsigned) gidsetsize > NGROUPS) + if ((unsigned)gidsetsize > NGROUPS_MAX) return -EINVAL; - if (copy_from_user(groups, grouplist, gidsetsize * sizeof(u16))) - return -EFAULT; - for (i = 0 ; i < gidsetsize ; i++) - current->groups[i] = (gid_t)groups[i]; - current->ngroups = gidsetsize; - return 0; + + group_info = groups_alloc(gidsetsize); + if (!group_info) + return -ENOMEM; + retval = groups16_from_user(group_info, grouplist); + if (retval) { + put_group_info(group_info); + return retval; + } + + retval = set_current_groups(group_info); + if (retval) + put_group_info(group_info); + + return retval; } asmlinkage long sys32_getuid16(void) --- diff/arch/sparc64/lib/rwlock.S 2003-11-25 15:24:57.000000000 +0000 +++ source/arch/sparc64/lib/rwlock.S 2004-02-09 10:39:51.000000000 +0000 @@ -85,5 +85,20 @@ __write_trylock_fail: retl mov 0, %o0 + + .globl __read_trylock +__read_trylock: /* %o0 = lock_ptr */ + ldsw [%o0], %g5 + brlz,pn %g5, 100f + add %g5, 1, %g7 + cas [%o0], %g5, %g7 + cmp %g5, %g7 + bne,pn %icc, __read_trylock + membar #StoreLoad | #StoreStore + retl + mov 1, %o0 +100: retl + mov 0, %o0 + rwlock_impl_end: --- diff/arch/sparc64/prom/printf.c 2003-05-21 11:50:14.000000000 +0100 +++ source/arch/sparc64/prom/printf.c 2004-02-09 10:39:51.000000000 +0000 @@ -40,7 +40,7 @@ int i; va_start(args, fmt); - i = vsnprintf(ppbuf, sizeof(ppbuf), fmt, args); + i = vscnprintf(ppbuf, sizeof(ppbuf), fmt, args); va_end(args); prom_write(ppbuf, i); --- diff/arch/um/Kconfig 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/um/Kconfig 2004-02-09 10:39:51.000000000 +0000 @@ -61,6 +61,20 @@ config NET bool "Networking support" + help + Unless you really know what you are doing, you should say Y here. + The reason is that some programs need kernel networking support even + when running on a stand-alone machine that isn't connected to any + other computer. If you are upgrading from an older kernel, you + should consider updating your networking tools too because changes + in the kernel and the tools often go hand in hand. The tools are + contained in the package net-tools, the location and version number + of which are given in Documentation/Changes. + + For a general introduction to Linux networking, it is highly + recommended to read the NET-HOWTO, available from + . + source "fs/Kconfig.binfmt" @@ -85,6 +99,19 @@ If you'd like to be able to work with files stored on the host, say Y or M here; otherwise say N. +config HPPFS + tristate "HoneyPot ProcFS" + help + hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc + entries to be overridden, removed, or fabricated from the host. + Its purpose is to allow a UML to appear to be a physical machine + by removing or changing anything in /proc which gives away the + identity of a UML. + + See http://user-mode-linux.sf.net/hppfs.html for more information. + + You only need this if you are setting up a UML honeypot. Otherwise, + it is safe to say 'N' here. config MCONSOLE bool "Management console" @@ -105,6 +132,16 @@ config MAGIC_SYSRQ bool "Magic SysRq key" depends on MCONSOLE + help + If you say Y here, you will have some control over the system even + if the system crashes for example during kernel debugging (e.g., you + will be able to flush the buffer cache to disk, reboot the system + immediately or dump some status information). This is accomplished + by pressing various keys while holding SysRq (Alt+PrintScreen). It + also works on a serial console (on PC hardware at least), if you + send a BREAK and then within 5 seconds a command keypress. The + keys are documented in Documentation/sysrq.txt. Don't say Y + unless you really know what this hack does. config HOST_2G_2G bool "2G/2G host address space split" @@ -160,6 +197,9 @@ config HIGHMEM bool "Highmem support" +config PROC_MM + bool "/proc/mm support" + config KERNEL_STACK_ORDER int "Kernel stack size order" default 2 @@ -168,6 +208,17 @@ be 1 << order pages. The default is OK unless you're running Valgrind on UML, in which case, set this to 3. +config UML_REAL_TIME_CLOCK + bool "Real-time Clock" + default y + help + This option makes UML time deltas match wall clock deltas. This should + normally be enabled. The exception would be if you are debugging with + UML and spend long times with UML stopped at a breakpoint. In this + case, when UML is restarted, it will call the timer enough times to make + up for the time spent at the breakpoint. This could result in a + noticable lag. If this is a problem, then disable this option. + endmenu source "init/Kconfig" @@ -240,6 +291,10 @@ config PT_PROXY bool "Enable ptrace proxy" depends on XTERM_CHAN && DEBUG_INFO + help + This option enables a debugging interface which allows gdb to debug + the kernel without needing to actually attach to kernel threads. + If you want to do kernel debugging, say Y here; otherwise say N. config GPROF bool "Enable gprof support" --- diff/arch/um/Kconfig_block 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/Kconfig_block 2004-02-09 10:39:51.000000000 +0000 @@ -29,6 +29,20 @@ wise choice too. In all other cases (for example, if you're just playing around with User-Mode Linux) you can choose N. +# Turn this back on when the driver actually works +# +#config BLK_DEV_COW +# tristate "COW block device" +# help +# This is a layered driver which sits above two other block devices. +# One is read-only, and the other is a read-write layer which stores +# all changes. This provides the illusion that the read-only layer +# can be mounted read-write and changed. + +config BLK_DEV_COW_COMMON + bool + default BLK_DEV_COW || BLK_DEV_UBD + config BLK_DEV_LOOP tristate "Loopback device support" --- diff/arch/um/Kconfig_net 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/Kconfig_net 2004-02-09 10:39:51.000000000 +0000 @@ -1,5 +1,5 @@ -menu "Network Devices" +menu "UML Network Devices" depends on NET # UML virtual driver @@ -176,73 +176,5 @@ Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp" - -# Below are hardware-independent drivers mirrored from -# drivers/net/Config.in. It would be nice if Linux -# had HW independent drivers separated from the other -# but it does not. Until then each non-ISA/PCI arch -# needs to provide it's own menu of network drivers -config DUMMY - tristate "Dummy net driver support" - -config BONDING - tristate "Bonding driver support" - -config EQUALIZER - tristate "EQL (serial line load balancing) support" - -config TUN - tristate "Universal TUN/TAP device driver support" - -config ETHERTAP - tristate "Ethertap network tap (OBSOLETE)" - depends on EXPERIMENTAL && NETLINK - -config PPP - tristate "PPP (point-to-point protocol) support" - -config PPP_MULTILINK - bool "PPP multilink support (EXPERIMENTAL)" - depends on PPP && EXPERIMENTAL - -config PPP_FILTER - bool "PPP filtering" - depends on PPP && FILTER - -config PPP_ASYNC - tristate "PPP support for async serial ports" - depends on PPP - -config PPP_SYNC_TTY - tristate "PPP support for sync tty ports" - depends on PPP - -config PPP_DEFLATE - tristate "PPP Deflate compression" - depends on PPP - -config PPP_BSDCOMP - tristate "PPP BSD-Compress compression" - depends on PPP - -config PPPOE - tristate "PPP over Ethernet (EXPERIMENTAL)" - depends on PPP && EXPERIMENTAL - -config SLIP - tristate "SLIP (serial line) support" - -config SLIP_COMPRESSED - bool "CSLIP compressed headers" - depends on SLIP=y - -config SLIP_SMART - bool "Keepalive and linefill" - depends on SLIP=y - -config SLIP_MODE_SLIP6 - bool "Six bit SLIP encapsulation" - depends on SLIP=y - endmenu --- diff/arch/um/Makefile 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -24,15 +24,17 @@ # Have to precede the include because the included Makefiles reference them. SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \ include/asm-um/sigcontext.h include/asm-um/processor.h \ - include/asm-um/ptrace.h include/asm-um/arch-signal.h + include/asm-um/ptrace.h include/asm-um/arch-signal.h \ + include/asm-um/module.h ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \ $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h -include $(ARCH_DIR)/Makefile-$(SUBARCH) -include $(ARCH_DIR)/Makefile-os-$(OS) +.PHONY: sys_prepare +sys_prepare: + @: MAKEFILE-$(CONFIG_MODE_TT) += Makefile-tt MAKEFILE-$(CONFIG_MODE_SKAS) += Makefile-skas @@ -41,6 +43,9 @@ include $(addprefix $(ARCH_DIR)/,$(MAKEFILE-y)) endif +include $(ARCH_DIR)/Makefile-$(SUBARCH) +include $(ARCH_DIR)/Makefile-os-$(OS) + EXTRAVERSION := $(EXTRAVERSION)-1um ARCH_INCLUDE = -I$(ARCH_DIR)/include @@ -52,14 +57,20 @@ CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ -D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \ - $(MODE_INCLUDE) + -Dsigprocmask=kernel_sigprocmask $(MODE_INCLUDE) LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc +# These are needed for clean and mrproper, since in that case .config is not +# included; the values here are meaningless + +CONFIG_NEST_LEVEL ?= 0 +CONFIG_KERNEL_HALF_GIGS ?= 0 + SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000) ifeq ($(CONFIG_MODE_SKAS), y) -$(SYS_HEADERS) : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h +$(SYS_HEADERS) : $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h endif include/linux/version.h: arch/$(ARCH)/Makefile @@ -98,17 +109,17 @@ CONFIG_KERNEL_STACK_ORDER ?= 2 STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] ) -AFLAGS_vmlinux.lds.o = -U$(SUBARCH) \ +AFLAGS_vmlinux.lds.o = $(shell echo -U$(SUBARCH) \ -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \ -DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE_TT) \ - -DKERNEL_STACK_SIZE=$(STACK_SIZE) + -DKERNEL_STACK_SIZE=$(STACK_SIZE)) -AFLAGS_$(LD_SCRIPT-y:.s=).o = $(AFLAGS_vmlinux.lds.o) -P -C -Uum +export AFLAGS_$(LD_SCRIPT-y:.s=).o = $(AFLAGS_vmlinux.lds.o) -P -C -Uum LD_SCRIPT-y := $(ARCH_DIR)/$(LD_SCRIPT-y) -$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE - $(call if_changed_dep,as_s_S) +#$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE +# $(call if_changed_dep,as_s_S) linux: vmlinux $(LD_SCRIPT-y) $(CC) -Wl,-T,$(LD_SCRIPT-y) $(LINK-y) $(LINK_WRAPS) \ @@ -116,16 +127,22 @@ USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS)) +USER_CFLAGS := $(patsubst -Dsigprocmask=kernel_sigprocmask,,$(USER_CFLAGS)) USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \ $(MODE_INCLUDE) # To get a definition of F_SETSIG USER_CFLAGS += -D_GNU_SOURCE +ifdef CONFIG_DEBUG_INFO +USER_CFLAGS += -g +endif + CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/uml.lds.s \ - $(ARCH_DIR)/dyn_link.ld.s $(GEN_HEADERS) + $(ARCH_DIR)/dyn_link.ld.s $(ARCH_DIR)/include/uml-config.h \ + $(GEN_HEADERS) -$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c +$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c sys_prepare $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< archmrproper: @@ -161,19 +178,23 @@ $(ARCH_DIR)/os: cd $(ARCH_DIR) && ln -sf os-$(OS) os -$(ARCH_DIR)/include/uml-config.h : +$(ARCH_DIR)/include/uml-config.h : $(TOPDIR)/include/linux/autoconf.h sed 's/ CONFIG/ UML_CONFIG/' $(TOPDIR)/include/linux/autoconf.h > $@ +filechk_$(ARCH_DIR)/include/task.h := $(ARCH_DIR)/util/mk_task + $(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task - $< > $@ + $(call filechk,$@) + +filechk_$(ARCH_DIR)/include/kern_constants.h := $(ARCH_DIR)/util/mk_constants $(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants - $< > $@ + $(call filechk,$@) -$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h \ - $(ARCH_DIR)/util FORCE ; +$(ARCH_DIR)/util/mk_task $(ARCH_DIR)/util/mk_constants : $(ARCH_DIR)/util \ + sys_prepare FORCE ; $(ARCH_DIR)/util: FORCE - @$(call descend,$@,) + $(MAKE) -f scripts/Makefile.build obj=$@ -export SUBARCH USER_CFLAGS OS +export SUBARCH USER_CFLAGS OS --- diff/arch/um/Makefile-i386 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/Makefile-i386 2004-02-09 10:39:51.000000000 +0000 @@ -16,22 +16,28 @@ SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h +sys_prepare: $(SYS_DIR)/sc.h + prepare: $(SYS_HEADERS) +filechk_$(SYS_DIR)/sc.h := $(SYS_UTIL_DIR)/mk_sc + $(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc - $< > $@ + $(call filechk,$@) + +filechk_$(SYS_DIR)/thread.h := $(SYS_UTIL_DIR)/mk_thread $(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread - $< > $@ + $(call filechk,$@) -$(SYS_UTIL_DIR)/mk_sc: FORCE ; - @$(call descend,$(SYS_UTIL_DIR),$@) +$(SYS_UTIL_DIR)/mk_sc: scripts/fixdep include/config/MARKER FORCE ; + +@$(call descend,$(SYS_UTIL_DIR),$@) -$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE ; - @$(call descend,$(SYS_UTIL_DIR),$@) +$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) sys_prepare FORCE ; + +@$(call descend,$(SYS_UTIL_DIR),$@) $(SYS_UTIL_DIR): include/asm FORCE - @$(call descend,$@,) + +@$(call descend,$@,) sysclean : rm -f $(SYS_HEADERS) --- diff/arch/um/Makefile-skas 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/Makefile-skas 2004-02-09 10:39:51.000000000 +0000 @@ -14,7 +14,7 @@ LINK_SKAS = -Wl,-rpath,/lib LD_SCRIPT_SKAS = dyn.lds.s -GEN_HEADERS += $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h +GEN_HEADERS += $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h -$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h : - $(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h +$(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h : + $(call descend,$(ARCH_DIR)/kernel/skas,$@) --- diff/arch/um/config.release 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/config.release 2004-02-09 10:39:51.000000000 +0000 @@ -228,7 +228,6 @@ CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m CONFIG_UDF_FS=m -# CONFIG_UDF_RW is not set CONFIG_UFS_FS=m # CONFIG_UFS_FS_WRITE is not set --- diff/arch/um/defconfig 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/defconfig 2004-02-09 10:39:51.000000000 +0000 @@ -3,29 +3,19 @@ # CONFIG_USERMODE=y CONFIG_MMU=y -CONFIG_SWAP=y CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_CONFIG_LOG_BUF_SHIFT=14 # -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# General Setup +# UML-specific options # CONFIG_MODE_TT=y CONFIG_MODE_SKAS=y CONFIG_NET=y -CONFIG_SYSVIPC=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_SYSCTL=y -CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y CONFIG_HOSTFS=y +CONFIG_HPPFS=y CONFIG_MCONSOLE=y CONFIG_MAGIC_SYSRQ=y # CONFIG_HOST_2G_2G is not set @@ -34,14 +24,43 @@ CONFIG_NEST_LEVEL=0 CONFIG_KERNEL_HALF_GIGS=1 # CONFIG_HIGHMEM is not set -CONFIG_PROC_MM=y +# CONFIG_PROC_MM is not set CONFIG_KERNEL_STACK_ORDER=2 +CONFIG_UML_REAL_TIME_CLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y # # Loadable module support # -CONFIG_MODULES=y -# CONFIG_KMOD is not set +# CONFIG_MODULES is not set + +# +# Generic Driver Options +# # # Character Devices @@ -69,6 +88,7 @@ # CONFIG_BLK_DEV_UBD=y # CONFIG_BLK_DEV_UBD_SYNC is not set +CONFIG_BLK_DEV_COW_COMMON=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y @@ -78,7 +98,7 @@ CONFIG_NETDEVICES=y # -# Network Devices +# UML Network Devices # CONFIG_UML_NET=y CONFIG_UML_NET_ETHERTAP=y @@ -88,22 +108,6 @@ CONFIG_UML_NET_MCAST=y # CONFIG_UML_NET_PCAP is not set CONFIG_UML_NET_SLIRP=y -CONFIG_DUMMY=y -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -CONFIG_TUN=y -# CONFIG_ETHERTAP is not set -CONFIG_PPP=y -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_ASYNC is not set -# CONFIG_PPP_SYNC_TTY is not set -# CONFIG_PPP_DEFLATE is not set -# CONFIG_PPP_BSDCOMP is not set -# CONFIG_PPPOE is not set -CONFIG_SLIP=y -# CONFIG_SLIP_COMPRESSED is not set -# CONFIG_SLIP_SMART is not set -# CONFIG_SLIP_MODE_SLIP6 is not set # # Networking support @@ -115,8 +119,6 @@ CONFIG_PACKET=y CONFIG_PACKET_MMAP=y # CONFIG_NETLINK_DEV is not set -# CONFIG_NETFILTER is not set -# CONFIG_FILTER is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -130,8 +132,11 @@ # CONFIG_SYN_COOKIES is not set # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set -# CONFIG_XFRM_USER is not set +# CONFIG_INET_IPCOMP is not set # CONFIG_IPV6 is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_NETFILTER is not set # # SCTP Configuration (EXPERIMENTAL) @@ -140,9 +145,9 @@ # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set -# CONFIG_LLC is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_NET_DIVERT is not set @@ -160,6 +165,10 @@ # Network testing # # CONFIG_NET_PKTGEN is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=y # # Ethernet (10 or 100Mbit) @@ -171,12 +180,28 @@ # # +# Ethernet (10000 Mbit) +# +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set +CONFIG_SLIP=y +# CONFIG_SLIP_COMPRESSED is not set +# CONFIG_SLIP_SMART is not set +# CONFIG_SLIP_MODE_SLIP6 is not set + +# # Wireless LAN (non-hamradio) # # CONFIG_NET_RADIO is not set # -# Token Ring devices (depends on LLC=y) +# Token Ring devices # # CONFIG_SHAPER is not set @@ -186,68 +211,101 @@ # CONFIG_WAN is not set # +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# Bluetooth support +# +# CONFIG_BT is not set + +# # File systems # +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +CONFIG_REISERFS_FS=y +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +CONFIG_MINIX_FS=y +# CONFIG_ROMFS_FS is not set CONFIG_QUOTA=y # CONFIG_QFMT_V1 is not set # CONFIG_QFMT_V2 is not set CONFIG_QUOTACTL=y -CONFIG_AUTOFS_FS=m -CONFIG_AUTOFS4_FS=m -CONFIG_REISERFS_FS=m -# CONFIG_REISERFS_CHECK is not set -# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_EXT3_FS is not set -# CONFIG_JBD is not set -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m # CONFIG_EFS_FS is not set CONFIG_JFFS_FS=y CONFIG_JFFS_FS_VERBOSE=0 -CONFIG_JFFS_PROC_FS=y # CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set -# CONFIG_TMPFS is not set -CONFIG_RAMFS=y -CONFIG_ISO9660_FS=m -# CONFIG_JOLIET is not set -# CONFIG_ZISOFS is not set -# CONFIG_JFS_FS is not set -CONFIG_MINIX_FS=m # CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set # CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set -# CONFIG_XFS_FS is not set # # Network File Systems # -# CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set # CONFIG_NFS_FS is not set # CONFIG_NFSD is not set # CONFIG_EXPORTFS is not set -# CONFIG_CIFS is not set # CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set # CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set # CONFIG_AFS_FS is not set # @@ -317,28 +375,7 @@ # # SCSI support # -CONFIG_SCSI=y -CONFIG_GENERIC_ISA_DMA=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -CONFIG_CHR_DEV_ST=y -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_SR_EXTRA_DEVS=2 -CONFIG_CHR_DEV_SG=y - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -CONFIG_SCSI_DEBUG_QUEUES=y -CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y -CONFIG_SCSI_DEBUG=y +# CONFIG_SCSI is not set # # Multi-device support (RAID and LVM) @@ -360,6 +397,7 @@ CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set # CONFIG_NFTL is not set +# CONFIG_INFTL is not set # # RAM/ROM/Flash chip drivers @@ -374,20 +412,21 @@ # # Mapping drivers for chip access # +# CONFIG_MTD_COMPLEX_MAPPINGS is not set # # Self-contained MTD device drivers # # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_MTDRAM is not set -CONFIG_MTD_BLKMTD=m +CONFIG_MTD_BLKMTD=y # # Disk-On-Chip Device Drivers # -# CONFIG_MTD_DOC1000 is not set # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set # # NAND Flash Device Drivers --- diff/arch/um/drivers/Makefile 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) +# Copyright (C) 2000, 2002, 2003 Jeff Dike (jdike@karaya.com) # Licensed under the GPL # @@ -39,6 +39,8 @@ obj-$(CONFIG_TTY_CHAN) += tty.o obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o obj-$(CONFIG_UML_WATCHDOG) += harddog.o +obj-$(CONFIG_BLK_DEV_COW) += cow_kern.o +obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o obj-y += stdio_console.o $(CHAN_OBJS) @@ -46,7 +48,7 @@ USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \ null.o pty.o tty.o xterm.o -USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/drivers/$(file)) +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< --- diff/arch/um/drivers/chan_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/chan_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include "chan_kern.h" @@ -265,6 +266,11 @@ { int n = 0; + if(chan == NULL){ + CONFIG_CHUNK(str, size, n, "none", 1); + return(n); + } + CONFIG_CHUNK(str, size, n, chan->ops->type, 0); if(chan->dev == NULL){ @@ -420,7 +426,8 @@ INIT_LIST_HEAD(chans); } - if((out = strchr(str, ',')) != NULL){ + out = strchr(str, ','); + if(out != NULL){ in = str; *out = '\0'; out++; @@ -475,12 +482,15 @@ goto out; } err = chan->ops->read(chan->fd, &c, chan->data); - if(err > 0) tty_receive_char(tty, c); + if(err > 0) + tty_receive_char(tty, c); } while(err > 0); + if(err == 0) reactivate_fd(chan->fd, irq); if(err == -EIO){ if(chan->primary){ - if(tty != NULL) tty_hangup(tty); + if(tty != NULL) + tty_hangup(tty); line_disable(dev, irq); close_chan(chans); free_chan(chans); --- diff/arch/um/drivers/chan_user.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/chan_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -24,29 +23,27 @@ void generic_close(int fd, void *unused) { - close(fd); + os_close_file(fd); } int generic_read(int fd, char *c_out, void *unused) { int n; - n = read(fd, c_out, sizeof(*c_out)); - if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); - } - else if(n == 0) return(-EIO); - return(1); + n = os_read_file(fd, c_out, sizeof(*c_out)); + + if(n == -EAGAIN) + return(0); + else if(n == 0) + return(-EIO); + return(n); } +/* XXX Trivial wrapper around os_write_file */ + int generic_write(int fd, const char *buf, int n, void *unused) { - int count; - - count = write(fd, buf, n); - if(count < 0) return(-errno); - return(count); + return(os_write_file(fd, buf, n)); } int generic_console_write(int fd, const char *buf, int n, void *unused) @@ -68,15 +65,18 @@ int generic_window_size(int fd, void *unused, unsigned short *rows_out, unsigned short *cols_out) { - struct winsize size; - int ret = 0; + int rows, cols; + int ret; + + ret = os_window_size(fd, &rows, &cols); + if(ret < 0) + return(ret); + + ret = ((*rows_out != rows) || (*cols_out != cols)); + + *rows_out = rows; + *cols_out = cols; - if(ioctl(fd, TIOCGWINSZ, &size) == 0){ - ret = ((*rows_out != size.ws_row) || - (*cols_out != size.ws_col)); - *rows_out = size.ws_row; - *cols_out = size.ws_col; - } return(ret); } @@ -100,14 +100,16 @@ struct winch_data *data = arg; sigset_t sigs; int pty_fd, pipe_fd; + int count, err; char c = 1; - close(data->close_me); + os_close_file(data->close_me); pty_fd = data->pty_fd; pipe_fd = data->pipe_fd; - if(write(pipe_fd, &c, sizeof(c)) != sizeof(c)) + count = os_write_file(pipe_fd, &c, sizeof(c)); + if(count != sizeof(c)) printk("winch_thread : failed to write synchronization " - "byte, errno = %d\n", errno); + "byte, err = %d\n", -count); signal(SIGWINCH, winch_handler); sigfillset(&sigs); @@ -123,26 +125,24 @@ exit(1); } - if(ioctl(pty_fd, TIOCSCTTY, 0) < 0){ - printk("winch_thread : TIOCSCTTY failed, errno = %d\n", errno); - exit(1); - } - if(tcsetpgrp(pty_fd, os_getpid()) < 0){ - printk("winch_thread : tcsetpgrp failed, errno = %d\n", errno); + err = os_new_tty_pgrp(pty_fd, os_getpid()); + if(err < 0){ + printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err); exit(1); } - if(read(pipe_fd, &c, sizeof(c)) != sizeof(c)) + count = os_read_file(pipe_fd, &c, sizeof(c)); + if(count != sizeof(c)) printk("winch_thread : failed to read synchronization byte, " - "errno = %d\n", errno); + "err = %d\n", -count); while(1){ pause(); - if(write(pipe_fd, &c, sizeof(c)) != sizeof(c)){ - printk("winch_thread : write failed, errno = %d\n", - errno); - } + count = os_write_file(pipe_fd, &c, sizeof(c)); + if(count != sizeof(c)) + printk("winch_thread : write failed, err = %d\n", + -count); } } @@ -154,8 +154,8 @@ char c; err = os_pipe(fds, 1, 1); - if(err){ - printk("winch_tramp : os_pipe failed, errno = %d\n", -err); + if(err < 0){ + printk("winch_tramp : os_pipe failed, err = %d\n", -err); return(err); } @@ -168,12 +168,12 @@ return(pid); } - close(fds[1]); + os_close_file(fds[1]); *fd_out = fds[0]; - n = read(fds[0], &c, sizeof(c)); + n = os_read_file(fds[0], &c, sizeof(c)); if(n != sizeof(c)){ printk("winch_tramp : failed to read synchronization byte\n"); - printk("read returned %d, errno = %d\n", n, errno); + printk("read failed, err = %d\n", -n); printk("fd %d will not support SIGWINCH\n", fd); *fd_out = -1; } @@ -183,20 +183,24 @@ void register_winch(int fd, void *device_data) { int pid, thread, thread_fd; + int count; char c = 1; - if(!isatty(fd)) return; + if(!isatty(fd)) + return; pid = tcgetpgrp(fd); - if(!CHOOSE_MODE(is_tracer_winch(pid, fd, device_data), 0) && - (pid == -1)){ + if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd, + device_data) && (pid == -1)){ thread = winch_tramp(fd, device_data, &thread_fd); if(fd != -1){ register_winch_irq(thread_fd, fd, thread, device_data); - if(write(thread_fd, &c, sizeof(c)) != sizeof(c)) + count = os_write_file(thread_fd, &c, sizeof(c)); + if(count != sizeof(c)) printk("register_winch : failed to write " - "synchronization byte\n"); + "synchronization byte, err = %d\n", + -count); } } } --- diff/arch/um/drivers/daemon_user.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/drivers/daemon_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -53,7 +53,8 @@ struct request_v3 req; int fd, n, err; - if((pri->control = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){ + pri->control = socket(AF_UNIX, SOCK_STREAM, 0); + if(pri->control < 0){ printk("daemon_open : control socket failed, errno = %d\n", errno); return(-errno); @@ -67,7 +68,8 @@ goto out; } - if((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){ + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if(fd < 0){ printk("daemon_open : data socket failed, errno = %d\n", errno); err = -errno; @@ -91,18 +93,18 @@ req.version = SWITCH_VERSION; req.type = REQ_NEW_CONTROL; req.sock = *local_addr; - n = write(pri->control, &req, sizeof(req)); + n = os_write_file(pri->control, &req, sizeof(req)); if(n != sizeof(req)){ - printk("daemon_open : control setup request returned %d, " - "errno = %d\n", n, errno); + printk("daemon_open : control setup request failed, err = %d\n", + -n); err = -ENOTCONN; goto out; } - n = read(pri->control, sun, sizeof(*sun)); + n = os_read_file(pri->control, sun, sizeof(*sun)); if(n != sizeof(*sun)){ - printk("daemon_open : read of data socket returned %d, " - "errno = %d\n", n, errno); + printk("daemon_open : read of data socket failed, err = %d\n", + -n); err = -ENOTCONN; goto out_close; } @@ -111,9 +113,9 @@ return(fd); out_close: - close(fd); + os_close_file(fd); out: - close(pri->control); + os_close_file(pri->control); return(err); } @@ -153,8 +155,8 @@ { struct daemon_data *pri = data; - close(pri->fd); - close(pri->control); + os_close_file(pri->fd); + os_close_file(pri->control); if(pri->data_addr != NULL) kfree(pri->data_addr); if(pri->ctl_addr != NULL) kfree(pri->ctl_addr); if(pri->local_addr != NULL) kfree(pri->local_addr); --- diff/arch/um/drivers/fd.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/drivers/fd.c 2004-02-09 10:39:51.000000000 +0000 @@ -35,7 +35,8 @@ printk("fd_init : couldn't parse file descriptor '%s'\n", str); return(NULL); } - if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL); + data = um_kmalloc(sizeof(*data)); + if(data == NULL) return(NULL); *data = ((struct fd_chan) { .fd = n, .raw = opts->raw }); return(data); --- diff/arch/um/drivers/harddog_user.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/drivers/harddog_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -27,10 +27,10 @@ dup2(data->stdin, 0); dup2(data->stdout, 1); dup2(data->stdout, 2); - close(data->stdin); - close(data->stdout); - close(data->close_me[0]); - close(data->close_me[1]); + os_close_file(data->stdin); + os_close_file(data->stdout); + os_close_file(data->close_me[0]); + os_close_file(data->close_me[1]); } int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) @@ -44,15 +44,15 @@ char **args = NULL; err = os_pipe(in_fds, 1, 0); - if(err){ - printk("harddog_open - os_pipe failed, errno = %d\n", -err); - return(err); + if(err < 0){ + printk("harddog_open - os_pipe failed, err = %d\n", -err); + goto out; } err = os_pipe(out_fds, 1, 0); - if(err){ - printk("harddog_open - os_pipe failed, errno = %d\n", -err); - return(err); + if(err < 0){ + printk("harddog_open - os_pipe failed, err = %d\n", -err); + goto out_close_in; } data.stdin = out_fds[0]; @@ -72,42 +72,47 @@ pid = run_helper(pre_exec, &data, args, NULL); - close(out_fds[0]); - close(in_fds[1]); + os_close_file(out_fds[0]); + os_close_file(in_fds[1]); if(pid < 0){ err = -pid; - printk("harddog_open - run_helper failed, errno = %d\n", err); - goto out; + printk("harddog_open - run_helper failed, errno = %d\n", -err); + goto out_close_out; } - n = read(in_fds[0], &c, sizeof(c)); + n = os_read_file(in_fds[0], &c, sizeof(c)); if(n == 0){ printk("harddog_open - EOF on watchdog pipe\n"); helper_wait(pid); err = -EIO; - goto out; + goto out_close_out; } else if(n < 0){ printk("harddog_open - read of watchdog pipe failed, " - "errno = %d\n", errno); + "err = %d\n", -n); helper_wait(pid); - err = -errno; - goto out; + err = n; + goto out_close_out; } *in_fd_ret = in_fds[0]; *out_fd_ret = out_fds[1]; return(0); + + out_close_in: + os_close_file(in_fds[0]); + os_close_file(in_fds[1]); + out_close_out: + os_close_file(out_fds[0]); + os_close_file(out_fds[1]); out: - close(out_fds[1]); - close(in_fds[0]); return(err); } void stop_watchdog(int in_fd, int out_fd) { - close(in_fd); - close(out_fd); + os_close_file(in_fd); + os_close_file(out_fd); } int ping_watchdog(int fd) @@ -115,11 +120,12 @@ int n; char c = '\n'; - n = write(fd, &c, sizeof(c)); - if(n < sizeof(c)){ - printk("ping_watchdog - write failed, errno = %d\n", - errno); - return(-errno); + n = os_write_file(fd, &c, sizeof(c)); + if(n != sizeof(c)){ + printk("ping_watchdog - write failed, err = %d\n", -n); + if(n < 0) + return(n); + return(-EIO); } return 1; --- diff/arch/um/drivers/hostaudio_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/hostaudio_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -5,12 +5,12 @@ #include "linux/config.h" #include "linux/module.h" -#include "linux/version.h" #include "linux/init.h" #include "linux/slab.h" #include "linux/fs.h" #include "linux/sound.h" #include "linux/soundcard.h" +#include "asm/uaccess.h" #include "kern_util.h" #include "init.h" #include "hostaudio.h" @@ -19,30 +19,39 @@ char *dsp = HOSTAUDIO_DEV_DSP; char *mixer = HOSTAUDIO_DEV_MIXER; +#define DSP_HELP \ +" This is used to specify the host dsp device to the hostaudio driver.\n" \ +" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n" + +#define MIXER_HELP \ +" This is used to specify the host mixer device to the hostaudio driver.\n" \ +" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n" + #ifndef MODULE static int set_dsp(char *name, int *add) { - dsp = uml_strdup(name); + dsp = name; return(0); } -__uml_setup("dsp=", set_dsp, -"dsp=\n" -" This is used to specify the host dsp device to the hostaudio driver.\n" -" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n" -); +__uml_setup("dsp=", set_dsp, "dsp=\n" DSP_HELP); static int set_mixer(char *name, int *add) { - mixer = uml_strdup(name); + mixer = name; return(0); } -__uml_setup("mixer=", set_mixer, -"mixer=\n" -" This is used to specify the host mixer device to the hostaudio driver.\n" -" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n" -); +__uml_setup("mixer=", set_mixer, "mixer=\n" MIXER_HELP); + +#else /*MODULE*/ + +MODULE_PARM(dsp, "s"); +MODULE_PARM_DESC(dsp, DSP_HELP); + +MODULE_PARM(mixer, "s"); +MODULE_PARM_DESC(mixer, MIXER_HELP); + #endif /* /dev/dsp file operations */ @@ -51,23 +60,55 @@ loff_t *ppos) { struct hostaudio_state *state = file->private_data; + void *kbuf; + int err; #ifdef DEBUG printk("hostaudio: read called, count = %d\n", count); #endif - return(hostaudio_read_user(state, buffer, count, ppos)); + kbuf = kmalloc(count, GFP_KERNEL); + if(kbuf == NULL) + return(-ENOMEM); + + err = hostaudio_read_user(state, kbuf, count, ppos); + if(err < 0) + goto out; + + if(copy_to_user(buffer, kbuf, err)) + err = -EFAULT; + + out: + kfree(kbuf); + return(err); } static ssize_t hostaudio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct hostaudio_state *state = file->private_data; + void *kbuf; + int err; #ifdef DEBUG printk("hostaudio: write called, count = %d\n", count); #endif - return(hostaudio_write_user(state, buffer, count, ppos)); + + kbuf = kmalloc(count, GFP_KERNEL); + if(kbuf == NULL) + return(-ENOMEM); + + err = -EFAULT; + if(copy_from_user(kbuf, buffer, count)) + goto out; + + err = hostaudio_write_user(state, kbuf, count, ppos); + if(err < 0) + goto out; + + out: + kfree(kbuf); + return(err); } static unsigned int hostaudio_poll(struct file *file, @@ -86,12 +127,43 @@ unsigned int cmd, unsigned long arg) { struct hostaudio_state *state = file->private_data; + unsigned long data = 0; + int err; #ifdef DEBUG printk("hostaudio: ioctl called, cmd = %u\n", cmd); #endif + switch(cmd){ + case SNDCTL_DSP_SPEED: + case SNDCTL_DSP_STEREO: + case SNDCTL_DSP_GETBLKSIZE: + case SNDCTL_DSP_CHANNELS: + case SNDCTL_DSP_SUBDIVIDE: + case SNDCTL_DSP_SETFRAGMENT: + if(get_user(data, (int *) arg)) + return(-EFAULT); + break; + default: + break; + } + + err = hostaudio_ioctl_user(state, cmd, (unsigned long) &data); + + switch(cmd){ + case SNDCTL_DSP_SPEED: + case SNDCTL_DSP_STEREO: + case SNDCTL_DSP_GETBLKSIZE: + case SNDCTL_DSP_CHANNELS: + case SNDCTL_DSP_SUBDIVIDE: + case SNDCTL_DSP_SETFRAGMENT: + if(put_user(data, (int *) arg)) + return(-EFAULT); + break; + default: + break; + } - return(hostaudio_ioctl_user(state, cmd, arg)); + return(err); } static int hostaudio_open(struct inode *inode, struct file *file) @@ -225,7 +297,8 @@ static int __init hostaudio_init_module(void) { - printk(KERN_INFO "UML Audio Relay\n"); + printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n", + dsp, mixer); module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1); if(module_data.dev_audio < 0){ --- diff/arch/um/drivers/hostaudio_user.c 2002-10-16 04:28:30.000000000 +0100 +++ source/arch/um/drivers/hostaudio_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -4,9 +4,6 @@ */ #include -#include -#include -#include #include #include #include "hostaudio.h" @@ -20,45 +17,31 @@ ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer, size_t count, loff_t *ppos) { - ssize_t ret; - #ifdef DEBUG printk("hostaudio: read_user called, count = %d\n", count); #endif - ret = read(state->fd, buffer, count); - - if(ret < 0) return(-errno); - return(ret); + return(os_read_file(state->fd, buffer, count)); } ssize_t hostaudio_write_user(struct hostaudio_state *state, const char *buffer, size_t count, loff_t *ppos) { - ssize_t ret; - #ifdef DEBUG printk("hostaudio: write_user called, count = %d\n", count); #endif - ret = write(state->fd, buffer, count); - - if(ret < 0) return(-errno); - return(ret); + return(os_write_file(state->fd, buffer, count)); } int hostaudio_ioctl_user(struct hostaudio_state *state, unsigned int cmd, unsigned long arg) { - int ret; #ifdef DEBUG printk("hostaudio: ioctl_user called, cmd = %u\n", cmd); #endif - ret = ioctl(state->fd, cmd, arg); - - if(ret < 0) return(-errno); - return(ret); + return(os_ioctl_generic(state->fd, cmd, arg)); } int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp) @@ -67,14 +50,15 @@ printk("hostaudio: open_user called\n"); #endif - state->fd = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); - - if(state->fd >= 0) return(0); + state->fd = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); - printk("hostaudio_open_user failed to open '%s', errno = %d\n", - dsp, errno); + if(state->fd < 0) { + printk("hostaudio_open_user failed to open '%s', err = %d\n", + dsp, -state->fd); + return(state->fd); + } - return(-errno); + return(0); } int hostaudio_release_user(struct hostaudio_state *state) @@ -82,10 +66,10 @@ #ifdef DEBUG printk("hostaudio: release called\n"); #endif - if(state->fd >= 0){ - close(state->fd); - state->fd=-1; - } + if(state->fd >= 0){ + os_close_file(state->fd); + state->fd = -1; + } return(0); } @@ -95,15 +79,11 @@ int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, unsigned int cmd, unsigned long arg) { - int ret; #ifdef DEBUG printk("hostmixer: ioctl_user called cmd = %u\n",cmd); #endif - ret = ioctl(state->fd, cmd, arg); - if(ret < 0) - return(-errno); - return(ret); + return(os_ioctl_generic(state->fd, cmd, arg)); } int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w, @@ -115,12 +95,13 @@ state->fd = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); - if(state->fd >= 0) return(0); - - printk("hostaudio_open_mixdev_user failed to open '%s', errno = %d\n", - mixer, errno); + if(state->fd < 0) { + printk("hostaudio_open_mixdev_user failed to open '%s', " + "err = %d\n", mixer, state->fd); + return(state->fd); + } - return(-errno); + return(0); } int hostmixer_release_mixdev_user(struct hostmixer_state *state) @@ -130,7 +111,7 @@ #endif if(state->fd >= 0){ - close(state->fd); + os_close_file(state->fd); state->fd = -1; } --- diff/arch/um/drivers/line.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/line.c 2004-02-09 10:39:51.000000000 +0000 @@ -6,8 +6,8 @@ #include "linux/sched.h" #include "linux/slab.h" #include "linux/list.h" +#include "linux/interrupt.h" #include "linux/devfs_fs_kernel.h" -#include "asm/irq.h" #include "asm/uaccess.h" #include "chan_kern.h" #include "irq_user.h" @@ -16,38 +16,55 @@ #include "user_util.h" #include "kern_util.h" #include "os.h" +#include "irq_kern.h" #define LINE_BUFSIZE 4096 -void line_interrupt(int irq, void *data, struct pt_regs *unused) +static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused) { struct line *dev = data; if(dev->count > 0) chan_interrupt(&dev->chan_list, &dev->task, dev->tty, irq, dev); + return IRQ_HANDLED; } -void line_timer_cb(void *arg) +static void line_timer_cb(void *arg) { struct line *dev = arg; line_interrupt(dev->driver->read_irq, dev, NULL); } -static void buffer_data(struct line *line, const char *buf, int len) +static int write_room(struct line *dev) { - int end; + int n; + + if(dev->buffer == NULL) return(LINE_BUFSIZE - 1); + + n = dev->head - dev->tail; + if(n <= 0) n = LINE_BUFSIZE + n; + return(n - 1); +} + +static int buffer_data(struct line *line, const char *buf, int len) +{ + int end, room; if(line->buffer == NULL){ line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC); if(line->buffer == NULL){ printk("buffer_data - atomic allocation failed\n"); - return; + return(0); } line->head = line->buffer; line->tail = line->buffer; } + + room = write_room(line); + len = (len > room) ? room : len; + end = line->buffer + LINE_BUFSIZE - line->tail; if(len < end){ memcpy(line->tail, buf, len); @@ -60,6 +77,8 @@ memcpy(line->buffer, buf, len); line->tail = line->buffer + len; } + + return(len); } static int flush_buffer(struct line *line) @@ -95,7 +114,7 @@ struct line *line; char *new; unsigned long flags; - int n, err, i; + int n, err, i, ret = 0; if(tty->stopped) return 0; @@ -104,9 +123,13 @@ if(new == NULL) return(0); n = copy_from_user(new, buf, len); - if(n == len) - return(-EFAULT); buf = new; + if(n == len){ + len = -EFAULT; + goto out_free; + } + + len -= n; } i = tty->index; @@ -115,41 +138,50 @@ down(&line->sem); if(line->head != line->tail){ local_irq_save(flags); - buffer_data(line, buf, len); + ret += buffer_data(line, buf, len); err = flush_buffer(line); local_irq_restore(flags); if(err <= 0) - goto out; + goto out_up; } else { n = write_chan(&line->chan_list, buf, len, line->driver->write_irq); if(n < 0){ - len = n; - goto out; + ret = n; + goto out_up; } - if(n < len) - buffer_data(line, buf + n, len - n); + + len -= n; + ret += n; + if(len > 0) + ret += buffer_data(line, buf + n, len); } - out: + out_up: up(&line->sem); - return(len); + out_free: + if(from_user) + kfree(buf); + return(ret); } -void line_write_interrupt(int irq, void *data, struct pt_regs *unused) +static irqreturn_t line_write_interrupt(int irq, void *data, + struct pt_regs *unused) { struct line *dev = data; struct tty_struct *tty = dev->tty; int err; err = flush_buffer(dev); - if(err == 0) return; + if(err == 0) + return(IRQ_NONE); else if(err < 0){ dev->head = dev->buffer; dev->tail = dev->buffer; } - if(tty == NULL) return; + if(tty == NULL) + return(IRQ_NONE); if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && (tty->ldisc.write_wakeup != NULL)) @@ -161,21 +193,9 @@ * writes. */ - if (waitqueue_active(&tty->write_wait)) + if(waitqueue_active(&tty->write_wait)) wake_up_interruptible(&tty->write_wait); - -} - -int line_write_room(struct tty_struct *tty) -{ - struct line *dev = tty->driver_data; - int n; - - if(dev->buffer == NULL) return(LINE_BUFSIZE - 1); - - n = dev->head - dev->tail; - if(n <= 0) n = LINE_BUFSIZE + n; - return(n - 1); + return(IRQ_HANDLED); } int line_setup_irq(int fd, int input, int output, void *data) @@ -305,7 +325,7 @@ if(*end != '='){ printk(KERN_ERR "line_setup failed to parse \"%s\"\n", init); - return(1); + return(0); } init = end; } @@ -313,12 +333,12 @@ if((n >= 0) && (n >= num)){ printk("line_setup - %d out of range ((0 ... %d) allowed)\n", n, num); - return(1); + return(0); } else if(n >= 0){ if(lines[n].count > 0){ printk("line_setup - device %d is open\n", n); - return(1); + return(0); } if(lines[n].init_pri <= INIT_ONE){ lines[n].init_pri = INIT_ONE; @@ -332,7 +352,7 @@ else if(!all_allowed){ printk("line_setup - can't configure all devices from " "mconsole\n"); - return(1); + return(0); } else { for(i = 0; i < num; i++){ @@ -346,7 +366,7 @@ } } } - return(0); + return(1); } int line_config(struct line *lines, int num, char *str) @@ -357,7 +377,7 @@ printk("line_config - uml_strdup failed\n"); return(-ENOMEM); } - return(line_setup(lines, num, new, 0)); + return(!line_setup(lines, num, new, 0)); } int line_get_config(char *name, struct line *lines, int num, char *str, @@ -369,7 +389,7 @@ dev = simple_strtoul(name, &end, 0); if((*end != '\0') || (end == name)){ - *error_out = "line_setup failed to parse device number"; + *error_out = "line_get_config failed to parse device number"; return(0); } @@ -379,15 +399,15 @@ } line = &lines[dev]; + down(&line->sem); - if(!line->valid) CONFIG_CHUNK(str, size, n, "none", 1); else if(line->count == 0) CONFIG_CHUNK(str, size, n, line->init_str, 1); else n = chan_config_string(&line->chan_list, str, size, error_out); - up(&line->sem); + return(n); } @@ -396,7 +416,14 @@ char config[sizeof("conxxxx=none\0")]; sprintf(config, "%s=none", str); - return(line_setup(lines, num, config, 0)); + return(!line_setup(lines, num, config, 0)); +} + +int line_write_room(struct tty_struct *tty) +{ + struct line *dev = tty->driver_data; + + return(write_room(dev)); } struct tty_driver *line_register_devfs(struct lines *set, @@ -412,7 +439,8 @@ return NULL; driver->driver_name = line_driver->name; - driver->name = line_driver->devfs_name; + driver->name = line_driver->device_name; + driver->devfs_name = line_driver->devfs_name; driver->major = line_driver->major; driver->minor_start = line_driver->minor_start; driver->type = line_driver->type; @@ -432,7 +460,7 @@ for(i = 0; i < nlines; i++){ if(!lines[i].valid) - tty_unregister_devfs(driver, i); + tty_unregister_device(driver, i); } mconsole_register_dev(&line_driver->mc); @@ -465,24 +493,25 @@ struct line *line; }; -void winch_interrupt(int irq, void *data, struct pt_regs *unused) +irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused) { struct winch *winch = data; struct tty_struct *tty; int err; char c; - err = generic_read(winch->fd, &c, NULL); - if(err < 0){ - if(err != -EAGAIN){ - printk("winch_interrupt : read failed, errno = %d\n", - -err); - printk("fd %d is losing SIGWINCH support\n", - winch->tty_fd); - free_irq(irq, data); - return; + if(winch->fd != -1){ + err = generic_read(winch->fd, &c, NULL); + if(err < 0){ + if(err != -EAGAIN){ + printk("winch_interrupt : read failed, " + "errno = %d\n", -err); + printk("fd %d is losing SIGWINCH support\n", + winch->tty_fd); + return(IRQ_HANDLED); + } + goto out; } - goto out; } tty = winch->line->tty; if(tty != NULL){ @@ -492,7 +521,9 @@ kill_pg(tty->pgrp, SIGWINCH, 1); } out: - reactivate_fd(winch->fd, WINCH_IRQ); + if(winch->fd != -1) + reactivate_fd(winch->fd, WINCH_IRQ); + return(IRQ_HANDLED); } DECLARE_MUTEX(winch_handler_sem); @@ -529,7 +560,10 @@ list_for_each(ele, &winch_handlers){ winch = list_entry(ele, struct winch, list); - close(winch->fd); + if(winch->fd != -1){ + deactivate_fd(winch->fd, WINCH_IRQ); + os_close_file(winch->fd); + } if(winch->pid != -1) os_kill_process(winch->pid, 1); } --- diff/arch/um/drivers/mcast_user.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/drivers/mcast_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -23,6 +23,7 @@ #include "kern_util.h" #include "user_util.h" #include "user.h" +#include "os.h" #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) @@ -62,7 +63,8 @@ goto out; } - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){ + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0){ printk("mcast_open : data socket failed, errno = %d\n", errno); fd = -ENOMEM; @@ -72,7 +74,7 @@ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { printk("mcast_open: SO_REUSEADDR failed, errno = %d\n", errno); - close(fd); + os_close_file(fd); fd = -EINVAL; goto out; } @@ -82,7 +84,7 @@ sizeof(pri->ttl)) < 0) { printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n", errno); - close(fd); + os_close_file(fd); fd = -EINVAL; goto out; } @@ -91,7 +93,7 @@ if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) { printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n", errno); - close(fd); + os_close_file(fd); fd = -EINVAL; goto out; } @@ -99,7 +101,7 @@ /* bind socket to mcast address */ if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) { printk("mcast_open : data bind failed, errno = %d\n", errno); - close(fd); + os_close_file(fd); fd = -EINVAL; goto out; } @@ -115,7 +117,7 @@ "interface on the host.\n"); printk("eth0 should be configured in order to use the " "multicast transport.\n"); - close(fd); + os_close_file(fd); fd = -EINVAL; } @@ -137,7 +139,7 @@ errno); } - close(fd); + os_close_file(fd); } int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri) --- diff/arch/um/drivers/mconsole_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/mconsole_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,6 +1,6 @@ /* * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -15,6 +15,9 @@ #include "linux/sysrq.h" #include "linux/workqueue.h" #include "linux/module.h" +#include "linux/file.h" +#include "linux/fs.h" +#include "linux/namei.h" #include "linux/proc_fs.h" #include "asm/irq.h" #include "asm/uaccess.h" @@ -27,6 +30,7 @@ #include "init.h" #include "os.h" #include "umid.h" +#include "irq_kern.h" static int do_unlink_socket(struct notifier_block *notifier, unsigned long what, void *data) @@ -67,7 +71,7 @@ DECLARE_WORK(mconsole_work, mc_work_proc, NULL); -void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int fd; struct mconsole_entry *new; @@ -75,9 +79,10 @@ fd = (int) dev_id; while (mconsole_get_request(fd, &req)){ - if(req.cmd->as_interrupt) (*req.cmd->handler)(&req); + if(req.cmd->context == MCONSOLE_INTR) + (*req.cmd->handler)(&req); else { - new = kmalloc(sizeof(req), GFP_ATOMIC); + new = kmalloc(sizeof(*new), GFP_ATOMIC); if(new == NULL) mconsole_reply(&req, "Out of memory", 1, 0); else { @@ -88,6 +93,7 @@ } if(!list_empty(&mc_requests)) schedule_work(&mconsole_work); reactivate_fd(fd, MCONSOLE_IRQ); + return(IRQ_HANDLED); } void mconsole_version(struct mc_request *req) @@ -100,20 +106,110 @@ mconsole_reply(req, version, 0, 0); } +void mconsole_log(struct mc_request *req) +{ + int len; + char *ptr = req->request.data; + + ptr += strlen("log"); + while(isspace(*ptr)) ptr++; + + len = req->len - (ptr - req->request.data); + printk("%.*s", len, ptr); + mconsole_reply(req, "", 0, 0); +} + +void mconsole_proc(struct mc_request *req) +{ + struct nameidata nd; + struct file_system_type *proc; + struct super_block *super; + struct file *file; + int n, err; + char *ptr = req->request.data, *buf; + + ptr += strlen("proc"); + while(isspace(*ptr)) ptr++; + + proc = get_fs_type("proc"); + if(proc == NULL){ + mconsole_reply(req, "procfs not registered", 1, 0); + goto out; + } + + super = (*proc->get_sb)(proc, 0, NULL, NULL); + put_filesystem(proc); + if(super == NULL){ + mconsole_reply(req, "Failed to get procfs superblock", 1, 0); + goto out; + } + up_write(&super->s_umount); + + nd.dentry = super->s_root; + nd.mnt = NULL; + nd.flags = O_RDONLY + 1; + nd.last_type = LAST_ROOT; + + err = link_path_walk(ptr, &nd); + if(err){ + mconsole_reply(req, "Failed to look up file", 1, 0); + goto out_kill; + } + + file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); + if(IS_ERR(file)){ + mconsole_reply(req, "Failed to open file", 1, 0); + goto out_kill; + } + + buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if(buf == NULL){ + mconsole_reply(req, "Failed to allocate buffer", 1, 0); + goto out_fput; + } + + if((file->f_op != NULL) && (file->f_op->read != NULL)){ + do { + n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1, + &file->f_pos); + if(n >= 0){ + buf[n] = '\0'; + mconsole_reply(req, buf, 0, (n > 0)); + } + else { + mconsole_reply(req, "Read of file failed", + 1, 0); + goto out_free; + } + } while(n > 0); + } + else mconsole_reply(req, "", 0, 0); + + out_free: + kfree(buf); + out_fput: + fput(file); + out_kill: + deactivate_super(super); + out: ; +} + #define UML_MCONSOLE_HELPTEXT \ -"Commands: - version - Get kernel version - help - Print this message - halt - Halt UML - reboot - Reboot UML - config = - Add a new device to UML; - same syntax as command line - config - Query the configuration of a device - remove - Remove a device from UML - sysrq - Performs the SysRq action controlled by the letter - cad - invoke the Ctl-Alt-Del handler - stop - pause the UML; it will do nothing until it receives a 'go' - go - continue the UML after a 'stop' +"Commands: \n\ + version - Get kernel version \n\ + help - Print this message \n\ + halt - Halt UML \n\ + reboot - Reboot UML \n\ + config = - Add a new device to UML; \n\ + same syntax as command line \n\ + config - Query the configuration of a device \n\ + remove - Remove a device from UML \n\ + sysrq - Performs the SysRq action controlled by the letter \n\ + cad - invoke the Ctl-Alt-Del handler \n\ + stop - pause the UML; it will do nothing until it receives a 'go' \n\ + go - continue the UML after a 'stop' \n\ + log - make UML enter into the kernel log\n\ + proc - returns the contents of the UML's /proc/\n\ " void mconsole_help(struct mc_request *req) @@ -302,7 +398,7 @@ if(umid_file_name("mconsole", file, sizeof(file))) return(-1); snprintf(mconsole_socket_name, sizeof(file), "%s", file); - sock = create_unix_socket(file, sizeof(file)); + sock = os_create_unix_socket(file, sizeof(file), 1); if (sock < 0){ printk("Failed to initialize management console\n"); return(1); @@ -344,11 +440,16 @@ if(buf == NULL) return(-ENOMEM); - if(copy_from_user(buf, buffer, count)) - return(-EFAULT); + if(copy_from_user(buf, buffer, count)){ + count = -EFAULT; + goto out; + } + buf[count] = '\0'; mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count); + out: + kfree(buf); return(count); } --- diff/arch/um/drivers/mconsole_user.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/mconsole_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,6 +1,6 @@ /* * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -18,16 +18,18 @@ #include "umid.h" static struct mconsole_command commands[] = { - { "version", mconsole_version, 1 }, - { "halt", mconsole_halt, 0 }, - { "reboot", mconsole_reboot, 0 }, - { "config", mconsole_config, 0 }, - { "remove", mconsole_remove, 0 }, - { "sysrq", mconsole_sysrq, 1 }, - { "help", mconsole_help, 1 }, - { "cad", mconsole_cad, 1 }, - { "stop", mconsole_stop, 0 }, - { "go", mconsole_go, 1 }, + { "version", mconsole_version, MCONSOLE_INTR }, + { "halt", mconsole_halt, MCONSOLE_PROC }, + { "reboot", mconsole_reboot, MCONSOLE_PROC }, + { "config", mconsole_config, MCONSOLE_PROC }, + { "remove", mconsole_remove, MCONSOLE_PROC }, + { "sysrq", mconsole_sysrq, MCONSOLE_INTR }, + { "help", mconsole_help, MCONSOLE_INTR }, + { "cad", mconsole_cad, MCONSOLE_INTR }, + { "stop", mconsole_stop, MCONSOLE_PROC }, + { "go", mconsole_go, MCONSOLE_INTR }, + { "log", mconsole_log, MCONSOLE_INTR }, + { "proc", mconsole_proc, MCONSOLE_PROC }, }; /* Initialized in mconsole_init, which is an initcall */ @@ -139,6 +141,7 @@ memcpy(reply.data, str, len); reply.data[len] = '\0'; total -= len; + str += len; reply.len = len + 1; len = sizeof(reply) + reply.len - sizeof(reply.data); --- diff/arch/um/drivers/mmapper_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/mmapper_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -120,7 +120,10 @@ printk(KERN_INFO "Mapper v0.1\n"); v_buf = (char *) find_iomem("mmapper", &mmapper_size); - if(mmapper_size == 0) return(0); + if(mmapper_size == 0){ + printk(KERN_ERR "mmapper_init - find_iomem failed\n"); + return(0); + } p_buf = __pa(v_buf); --- diff/arch/um/drivers/net_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/net_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -26,6 +26,7 @@ #include "mconsole_kern.h" #include "init.h" #include "irq_user.h" +#include "irq_kern.h" static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED; LIST_HEAD(opened); @@ -37,7 +38,8 @@ struct sk_buff *skb; /* If we can't allocate memory, try again next round. */ - if ((skb = dev_alloc_skb(dev->mtu)) == NULL) { + skb = dev_alloc_skb(dev->mtu); + if (skb == NULL) { lp->stats.rx_dropped++; return 0; } @@ -61,14 +63,14 @@ return pkt_len; } -void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; struct uml_net_private *lp = dev->priv; int err; if(!netif_running(dev)) - return; + return(IRQ_NONE); spin_lock(&lp->lock); while((err = uml_net_rx(dev)) > 0) ; @@ -83,6 +85,7 @@ out: spin_unlock(&lp->lock); + return(IRQ_HANDLED); } static int uml_net_open(struct net_device *dev) @@ -252,37 +255,6 @@ #endif } -/* - * default do nothing hard header packet routines for struct net_device init. - * real ethernet transports will overwrite with real routines. - */ -static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - return(0); /* no change */ -} - -static int uml_net_rebuild_header(struct sk_buff *skb) -{ - return(0); /* ignore */ -} - -static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh) -{ - return(-1); /* fail */ -} - -static void uml_net_header_cache_update(struct hh_cache *hh, - struct net_device *dev, unsigned char * haddr) -{ - /* ignore */ -} - -static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr) -{ - return(0); /* nothing */ -} - static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED; static struct list_head devices = LIST_HEAD_INIT(devices); @@ -292,7 +264,7 @@ struct uml_net *device; struct net_device *dev; struct uml_net_private *lp; - int err, size; + int save, err, size; size = transport->private_size + sizeof(struct uml_net_private) + sizeof(((struct uml_net_private *) 0)->user); @@ -334,12 +306,6 @@ snprintf(dev->name, sizeof(dev->name), "eth%d", n); device->dev = dev; - dev->hard_header = uml_net_hard_header; - dev->rebuild_header = uml_net_rebuild_header; - dev->hard_header_cache = uml_net_header_cache; - dev->header_cache_update= uml_net_header_cache_update; - dev->hard_header_parse = uml_net_header_parse; - (*transport->kern->init)(dev, init); dev->mtu = transport->user->max_packet; @@ -358,25 +324,37 @@ rtnl_lock(); err = register_netdevice(dev); rtnl_unlock(); - if (err) + if (err) { + device->dev = NULL; + /* XXX: should we call ->remove() here? */ + free_netdev(dev); return 1; + } lp = dev->priv; - INIT_LIST_HEAD(&lp->list); - spin_lock_init(&lp->lock); - lp->dev = dev; - lp->fd = -1; - lp->mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 }; - lp->have_mac = device->have_mac; - lp->protocol = transport->kern->protocol; - lp->open = transport->user->open; - lp->close = transport->user->close; - lp->remove = transport->user->remove; - lp->read = transport->kern->read; - lp->write = transport->kern->write; - lp->add_address = transport->user->add_address; - lp->delete_address = transport->user->delete_address; - lp->set_mtu = transport->user->set_mtu; + /* lp.user is the first four bytes of the transport data, which + * has already been initialized. This structure assignment will + * overwrite that, so we make sure that .user gets overwritten with + * what it already has. + */ + save = lp->user[0]; + *lp = ((struct uml_net_private) + { .list = LIST_HEAD_INIT(lp->list), + .lock = SPIN_LOCK_UNLOCKED, + .dev = dev, + .fd = -1, + .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0}, + .have_mac = device->have_mac, + .protocol = transport->kern->protocol, + .open = transport->user->open, + .close = transport->user->close, + .remove = transport->user->remove, + .read = transport->kern->read, + .write = transport->kern->write, + .add_address = transport->user->add_address, + .delete_address = transport->user->delete_address, + .set_mtu = transport->user->set_mtu, + .user = { save } }); init_timer(&lp->tl); lp->tl.function = uml_net_user_timer_expire; @@ -609,7 +587,8 @@ unregister_netdev(dev); list_del(&device->list); - free_netdev(device); + kfree(device); + free_netdev(dev); return(0); } --- diff/arch/um/drivers/net_user.c 2002-10-16 04:27:19.000000000 +0100 +++ source/arch/um/drivers/net_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -26,8 +26,7 @@ if(gate_addr == NULL) return(0); if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){ - printk("Invalid tap IP address - '%s'\n", - gate_addr); + printk("Invalid tap IP address - '%s'\n", gate_addr); return(-EINVAL); } return(0); @@ -60,18 +59,18 @@ } *output = '\0'; - if(read(fd, &remain, sizeof(remain)) != sizeof(remain)){ - printk("read_output - read of length failed, errno = %d\n", - errno); + n = os_read_file(fd, &remain, sizeof(remain)); + if(n != sizeof(remain)){ + printk("read_output - read of length failed, err = %d\n", -n); return; } while(remain != 0){ n = (remain < len) ? remain : len; - actual = read(fd, output, n); + actual = os_read_file(fd, output, n); if(actual != n){ printk("read_output - read of data failed, " - "errno = %d\n", errno); + "err = %d\n", -actual); return; } remain -= actual; @@ -83,13 +82,12 @@ { int n; - while(((n = read(fd, buf, len)) < 0) && (errno == EINTR)) ; + n = os_read_file(fd, buf, len); - if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); - } - else if(n == 0) return(-ENOTCONN); + if(n == -EAGAIN) + return(0); + else if(n == 0) + return(-ENOTCONN); return(n); } @@ -112,13 +110,13 @@ { int n; - while(((n = write(fd, buf, len)) < 0) && (errno == EINTR)) ; - if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); - } - else if(n == 0) return(-ENOTCONN); - return(n); + n = os_write_file(fd, buf, len); + + if(n == -EAGAIN) + return(0); + else if(n == 0) + return(-ENOTCONN); + return(n); } int net_send(int fd, void *buf, int len) @@ -157,7 +155,7 @@ { struct change_pre_exec_data *data = arg; - close(data->close_me); + os_close_file(data->close_me); dup2(data->stdout, 1); } @@ -167,15 +165,15 @@ struct change_pre_exec_data pe_data; err = os_pipe(fds, 1, 0); - if(err){ - printk("change_tramp - pipe failed, errno = %d\n", -err); + if(err < 0){ + printk("change_tramp - pipe failed, err = %d\n", -err); return(err); } pe_data.close_me = fds[0]; pe_data.stdout = fds[1]; pid = run_helper(change_pre_exec, &pe_data, argv, NULL); - close(fds[1]); + os_close_file(fds[1]); read_output(fds[0], output, output_len); waitpid(pid, NULL, 0); return(pid); --- diff/arch/um/drivers/null.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/drivers/null.c 2004-02-09 10:39:51.000000000 +0000 @@ -5,7 +5,6 @@ #include #include -#include #include "chan_user.h" #include "os.h" --- diff/arch/um/drivers/port_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/port_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -6,6 +6,7 @@ #include "linux/list.h" #include "linux/sched.h" #include "linux/slab.h" +#include "linux/interrupt.h" #include "linux/irq.h" #include "linux/spinlock.h" #include "linux/errno.h" @@ -14,6 +15,7 @@ #include "kern_util.h" #include "kern.h" #include "irq_user.h" +#include "irq_kern.h" #include "port.h" #include "init.h" #include "os.h" @@ -38,21 +40,21 @@ struct connection { struct list_head list; int fd; - int helper_pid; + int helper_pid; int socket[2]; int telnetd_pid; struct port_list *port; }; -static void pipe_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs) { struct connection *conn = data; int fd; - fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); + fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); if(fd < 0){ if(fd == -EAGAIN) - return; + return(IRQ_NONE); printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", -fd); @@ -65,6 +67,7 @@ list_add(&conn->list, &conn->port->connections); up(&conn->port->sem); + return(IRQ_HANDLED); } static int port_accept(struct port_list *port) @@ -102,8 +105,7 @@ } list_add(&conn->list, &port->pending); - ret = 1; - goto out; + return(1); out_free: kfree(conn); @@ -138,12 +140,13 @@ DECLARE_WORK(port_work, port_work_proc, NULL); -static void port_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs) { struct port_list *port = data; port->has_connection = 1; schedule_work(&port_work); + return(IRQ_HANDLED); } void *port_data(int port_num) --- diff/arch/um/drivers/port_user.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/drivers/port_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -47,10 +47,12 @@ return(NULL); } - if((kern_data = port_data(port)) == NULL) + kern_data = port_data(port); + if(kern_data == NULL) return(NULL); - if((data = um_kmalloc(sizeof(*data))) == NULL) + data = um_kmalloc(sizeof(*data)); + if(data == NULL) goto err; *data = ((struct port_chan) { .raw = opts->raw, @@ -90,7 +92,7 @@ struct port_chan *data = d; port_remove_dev(data->kernel_data); - close(fd); + os_close_file(fd); } int port_console_write(int fd, const char *buf, int n, void *d) @@ -130,11 +132,15 @@ goto out; } - if((listen(fd, 1) < 0) || (os_set_fd_block(fd, 0))){ + if(listen(fd, 1) < 0){ err = -errno; goto out; } + err = os_set_fd_block(fd, 0); + if(err < 0) + goto out; + return(fd); out: os_close_file(fd); @@ -153,10 +159,10 @@ dup2(data->sock_fd, 0); dup2(data->sock_fd, 1); dup2(data->sock_fd, 2); - close(data->sock_fd); + os_close_file(data->sock_fd); dup2(data->pipe_fd, 3); os_shutdown_socket(3, 1, 0); - close(data->pipe_fd); + os_close_file(data->pipe_fd); } int port_connection(int fd, int *socket, int *pid_out) @@ -166,11 +172,12 @@ "/usr/lib/uml/port-helper", NULL }; struct port_pre_exec_data data; - if((new = os_accept_connection(fd)) < 0) - return(-errno); + new = os_accept_connection(fd); + if(new < 0) + return(new); err = os_pipe(socket, 0, 0); - if(err) + if(err < 0) goto out_close; data = ((struct port_pre_exec_data) @@ -186,11 +193,11 @@ out_shutdown: os_shutdown_socket(socket[0], 1, 1); - close(socket[0]); + os_close_file(socket[0]); os_shutdown_socket(socket[1], 1, 1); - close(socket[1]); + os_close_file(socket[1]); out_close: - close(new); + os_close_file(new); return(err); } --- diff/arch/um/drivers/pty.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/drivers/pty.c 2004-02-09 10:39:51.000000000 +0000 @@ -7,12 +7,12 @@ #include #include #include -#include #include #include "chan_user.h" #include "user.h" #include "user_util.h" #include "kern_util.h" +#include "os.h" struct pty_chan { void (*announce)(char *dev_name, int dev); @@ -26,7 +26,8 @@ { struct pty_chan *data; - if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL); + data = um_kmalloc(sizeof(*data)); + if(data == NULL) return(NULL); *data = ((struct pty_chan) { .announce = opts->announce, .dev = device, .raw = opts->raw }); @@ -39,7 +40,8 @@ char *dev; int fd; - if((fd = get_pty()) < 0){ + fd = get_pty(); + if(fd < 0){ printk("open_pts : Failed to open pts\n"); return(-errno); } @@ -57,29 +59,27 @@ int getmaster(char *line) { - struct stat stb; char *pty, *bank, *cp; - int master; + int master, err; pty = &line[strlen("/dev/ptyp")]; for (bank = "pqrs"; *bank; bank++) { line[strlen("/dev/pty")] = *bank; *pty = '0'; - if (stat(line, &stb) < 0) + if (os_stat_file(line, NULL) < 0) break; for (cp = "0123456789abcdef"; *cp; cp++) { *pty = *cp; - master = open(line, O_RDWR); + master = os_open_file(line, of_rdwr(OPENFLAGS()), 0); if (master >= 0) { char *tp = &line[strlen("/dev/")]; - int ok; /* verify slave side is usable */ *tp = 't'; - ok = access(line, R_OK|W_OK) == 0; + err = os_access(line, OS_ACC_RW_OK); *tp = 'p'; - if (ok) return(master); - (void) close(master); + if(err == 0) return(master); + (void) os_close_file(master); } } } --- diff/arch/um/drivers/slip_user.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/drivers/slip_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -4,11 +4,9 @@ #include #include #include -#include #include #include #include -#include #include #include "user_util.h" #include "kern_util.h" @@ -65,9 +63,9 @@ { struct slip_pre_exec_data *data = arg; - if(data->stdin != -1) dup2(data->stdin, 0); + if(data->stdin >= 0) dup2(data->stdin, 0); dup2(data->stdout, 1); - if(data->close_me != -1) close(data->close_me); + if(data->close_me >= 0) os_close_file(data->close_me); } static int slip_tramp(char **argv, int fd) @@ -77,8 +75,8 @@ int status, pid, fds[2], err, output_len; err = os_pipe(fds, 1, 0); - if(err){ - printk("slip_tramp : pipe failed, errno = %d\n", -err); + if(err < 0){ + printk("slip_tramp : pipe failed, err = %d\n", -err); return(err); } @@ -96,7 +94,7 @@ printk("slip_tramp : failed to allocate output " "buffer\n"); - close(fds[1]); + os_close_file(fds[1]); read_output(fds[0], output, output_len); if(output != NULL){ printk("%s", output); @@ -105,7 +103,7 @@ if(waitpid(pid, &status, 0) < 0) err = errno; else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){ printk("'%s' didn't exit with status 0\n", argv[0]); - err = EINVAL; + err = -EINVAL; } } return(err); @@ -118,15 +116,17 @@ char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, NULL }; - int sfd, mfd, disc, sencap, err; + int sfd, mfd, err; - if((mfd = get_pty()) < 0){ - printk("umn : Failed to open pty\n"); - return(-1); + mfd = get_pty(); + if(mfd < 0){ + printk("umn : Failed to open pty, err = %d\n", -mfd); + return(mfd); } - if((sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0)) < 0){ - printk("Couldn't open tty for slip line\n"); - return(-1); + sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0); + if(sfd < 0){ + printk("Couldn't open tty for slip line, err = %d\n", -sfd); + return(sfd); } if(set_up_tty(sfd)) return(-1); pri->slave = sfd; @@ -138,28 +138,23 @@ err = slip_tramp(argv, sfd); - if(err != 0){ - printk("slip_tramp failed - errno = %d\n", err); - return(-err); + if(err < 0){ + printk("slip_tramp failed - err = %d\n", -err); + return(err); } - if(ioctl(pri->slave, SIOCGIFNAME, pri->name) < 0){ - printk("SIOCGIFNAME failed, errno = %d\n", errno); - return(-errno); + err = os_get_ifname(pri->slave, pri->name); + if(err < 0){ + printk("get_ifname failed, err = %d\n", -err); + return(err); } iter_addresses(pri->dev, open_addr, pri->name); } else { - disc = N_SLIP; - if(ioctl(sfd, TIOCSETD, &disc) < 0){ - printk("Failed to set slip line discipline - " - "errno = %d\n", errno); - return(-errno); - } - sencap = 0; - if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){ - printk("Failed to set slip encapsulation - " - "errno = %d\n", errno); - return(-errno); + err = os_set_slip(sfd); + if(err < 0){ + printk("Failed to set slip discipline encapsulation - " + "err = %d\n", -err); + return(err); } } return(mfd); @@ -181,9 +176,9 @@ err = slip_tramp(argv, -1); if(err != 0) - printk("slip_tramp failed - errno = %d\n", err); - close(fd); - close(pri->slave); + printk("slip_tramp failed - errno = %d\n", -err); + os_close_file(fd); + os_close_file(pri->slave); pri->slave = -1; } @@ -243,7 +238,7 @@ { struct slip_data *pri = data; - if(pri->slave == -1) return; + if(pri->slave < 0) return; open_addr(addr, netmask, pri->name); } @@ -252,7 +247,7 @@ { struct slip_data *pri = data; - if(pri->slave == -1) return; + if(pri->slave < 0) return; close_addr(addr, netmask, pri->name); } --- diff/arch/um/drivers/slirp_user.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/drivers/slirp_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -48,15 +47,15 @@ return(pid); } - + +/* XXX This is just a trivial wrapper around os_pipe */ static int slirp_datachan(int *mfd, int *sfd) { int fds[2], err; err = os_pipe(fds, 1, 1); - if(err){ - printk("slirp_datachan: Failed to open pipe, errno = %d\n", - -err); + if(err < 0){ + printk("slirp_datachan: Failed to open pipe, err = %d\n", -err); return(err); } @@ -77,7 +76,7 @@ pid = slirp_tramp(pri->argw.argv, sfd); if(pid < 0){ - printk("slirp_tramp failed - errno = %d\n", pid); + printk("slirp_tramp failed - errno = %d\n", -pid); os_close_file(sfd); os_close_file(mfd); return(pid); @@ -97,8 +96,8 @@ struct slirp_data *pri = data; int status,err; - close(fd); - close(pri->slave); + os_close_file(fd); + os_close_file(pri->slave); pri->slave = -1; --- diff/arch/um/drivers/ssl.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/ssl.c 2004-02-09 10:39:51.000000000 +0000 @@ -10,6 +10,7 @@ #include "linux/major.h" #include "linux/mm.h" #include "linux/init.h" +#include "linux/console.h" #include "asm/termbits.h" #include "asm/irq.h" #include "line.h" @@ -53,8 +54,9 @@ static struct line_driver driver = { .name = "UML serial line", - .devfs_name = "tts/%d", - .major = TTYAUX_MAJOR, + .device_name = "ttS", + .devfs_name = "tts/", + .major = TTY_MAJOR, .minor_start = 64, .type = TTY_DRIVER_TYPE_SERIAL, .subtype = 0, @@ -149,6 +151,9 @@ case TCSETSW: case TCGETA: case TIOCMGET: + case TCSBRK: + case TCSBRKP: + case TIOCMSET: ret = -ENOIOCTLCMD; break; default: @@ -212,6 +217,39 @@ */ static int ssl_init_done = 0; +extern int tty_init(void); + +static void ssl_console_write(struct console *c, const char *string, + unsigned len) +{ + struct line *line = &serial_lines[c->index]; + if(ssl_init_done) + down(&line->sem); + console_write_chan(&line->chan_list, string, len); + if(ssl_init_done) + up(&line->sem); +} + +static struct tty_driver *ssl_console_device(struct console *c, int *index) +{ + *index = c->index; + return ssl_driver; +} + +static int ssl_console_setup(struct console *co, char *options) +{ + return(0); +} + +static struct console ssl_cons = { + name: "ttyS", + write: ssl_console_write, + device: ssl_console_device, + setup: ssl_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + int ssl_init(void) { char *new_title; @@ -219,6 +257,8 @@ printk(KERN_INFO "Initializing software serial port version %d\n", ssl_version); + tty_init(); + ssl_driver = line_register_devfs(&lines, &driver, &ssl_ops, serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0])); @@ -227,6 +267,7 @@ new_title = add_xterm_umid(opts.xterm_title); if(new_title != NULL) opts.xterm_title = new_title; + register_console(&ssl_cons); ssl_init_done = 1; return(0); } @@ -235,9 +276,9 @@ static int ssl_chan_setup(char *str) { - line_setup(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]), - str, 1); - return(1); + return(line_setup(serial_lines, + sizeof(serial_lines)/sizeof(serial_lines[0]), + str, 1)); } __setup("ssl", ssl_chan_setup); --- diff/arch/um/drivers/stdio_console.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/stdio_console.c 2004-02-09 10:39:51.000000000 +0000 @@ -83,7 +83,8 @@ static struct line_driver driver = { .name = "UML console", - .devfs_name = "vc/%d", + .device_name = "tty", + .devfs_name = "vc/", .major = TTY_MAJOR, .minor_start = 0, .type = TTY_DRIVER_TYPE_CONSOLE, @@ -159,14 +160,28 @@ static int con_init_done = 0; +static struct tty_operations console_ops = { + .open = con_open, + .close = con_close, + .write = con_write, + .chars_in_buffer = chars_in_buffer, + .set_termios = set_termios, + .write_room = line_write_room, +}; + +extern int tty_init(void); + int stdio_init(void) { char *new_title; printk(KERN_INFO "Initializing stdio console driver\n"); + tty_init(); + console_driver = line_register_devfs(&console_lines, &driver, - &console_ops, vts, sizeof(vts)/sizeof(vts[0])); + &console_ops, vts, + sizeof(vts)/sizeof(vts[0])); lines_init(vts, sizeof(vts)/sizeof(vts[0])); @@ -183,19 +198,14 @@ static void console_write(struct console *console, const char *string, unsigned len) { - if(con_init_done) down(&vts[console->index].sem); - console_write_chan(&vts[console->index].chan_list, string, len); - if(con_init_done) up(&vts[console->index].sem); -} + struct line *line = &vts[console->index]; -static struct tty_operations console_ops = { - .open = con_open, - .close = con_close, - .write = con_write, - .chars_in_buffer = chars_in_buffer, - .set_termios = set_termios, - .write_room = line_write_room, -}; + if(con_init_done) + down(&line->sem); + console_write_chan(&line->chan_list, string, len); + if(con_init_done) + up(&line->sem); +} static struct tty_driver *console_device(struct console *c, int *index) { @@ -208,22 +218,28 @@ return(0); } -static struct console stdiocons = INIT_CONSOLE("tty", console_write, - console_device, console_setup, - CON_PRINTBUFFER); +static struct console stdiocons = { + name: "tty", + write: console_write, + device: console_device, + setup: console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; -static void __init stdio_console_init(void) +static int __init stdio_console_init(void) { INIT_LIST_HEAD(&vts[0].chan_list); list_add(&init_console_chan.list, &vts[0].chan_list); register_console(&stdiocons); + return(0); } + console_initcall(stdio_console_init); static int console_chan_setup(char *str) { - line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1); - return(1); + return(line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1)); } __setup("con", console_chan_setup); --- diff/arch/um/drivers/tty.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/drivers/tty.c 2004-02-09 10:39:51.000000000 +0000 @@ -5,7 +5,6 @@ #include #include -#include #include #include #include "chan_user.h" @@ -30,7 +29,8 @@ } str++; - if((data = um_kmalloc(sizeof(*data))) == NULL) + data = um_kmalloc(sizeof(*data)); + if(data == NULL) return(NULL); *data = ((struct tty_chan) { .dev = str, .raw = opts->raw }); --- diff/arch/um/drivers/ubd_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/ubd_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -8,6 +8,13 @@ * old style ubd by setting UBD_SHIFT to 0 * 2002-09-27...2002-10-18 massive tinkering for 2.5 * partitions have changed in 2.5 + * 2003-01-29 more tinkering for 2.5.59-1 + * This should now address the sysfs problems and has + * the symlink for devfs to allow for booting with + * the common /dev/ubd/discX/... names rather than + * only /dev/ubdN/discN this version also has lots of + * clean ups preparing for ubd-many. + * James McMechan */ #define MAJOR_NR UBD_MAJOR @@ -40,9 +47,12 @@ #include "mconsole_kern.h" #include "init.h" #include "irq_user.h" +#include "irq_kern.h" #include "ubd_user.h" #include "2_5compat.h" #include "os.h" +#include "mem.h" +#include "mem_kern.h" static spinlock_t ubd_io_lock = SPIN_LOCK_UNLOCKED; static spinlock_t ubd_lock = SPIN_LOCK_UNLOCKED; @@ -56,6 +66,10 @@ #define MAX_DEV (8) +/* Changed in early boot */ +static int ubd_do_mmap = 0; +#define UBD_MMAP_BLOCK_SIZE PAGE_SIZE + static struct block_device_operations ubd_blops = { .owner = THIS_MODULE, .open = ubd_open, @@ -67,7 +81,7 @@ static request_queue_t *ubd_queue; /* Protected by ubd_lock */ -static int fake_major = 0; +static int fake_major = MAJOR_NR; static struct gendisk *ubd_gendisk[MAX_DEV]; static struct gendisk *fake_gendisk[MAX_DEV]; @@ -96,13 +110,19 @@ struct ubd { char *file; - int is_dir; int count; int fd; __u64 size; struct openflags boot_openflags; struct openflags openflags; + int no_cow; struct cow cow; + + int map_writes; + int map_reads; + int nomap_writes; + int nomap_reads; + int write_maps; }; #define DEFAULT_COW { \ @@ -115,21 +135,28 @@ #define DEFAULT_UBD { \ .file = NULL, \ - .is_dir = 0, \ .count = 0, \ .fd = -1, \ .size = -1, \ .boot_openflags = OPEN_FLAGS, \ .openflags = OPEN_FLAGS, \ + .no_cow = 0, \ .cow = DEFAULT_COW, \ + .map_writes = 0, \ + .map_reads = 0, \ + .nomap_writes = 0, \ + .nomap_reads = 0, \ + .write_maps = 0, \ } struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; static int ubd0_init(void) { - if(ubd_dev[0].file == NULL) - ubd_dev[0].file = "root_fs"; + struct ubd *dev = &ubd_dev[0]; + + if(dev->file == NULL) + dev->file = "root_fs"; return(0); } @@ -196,19 +223,46 @@ " Create ide0 entries that map onto ubd devices.\n\n" ); +static int parse_unit(char **ptr) +{ + char *str = *ptr, *end; + int n = -1; + + if(isdigit(*str)) { + n = simple_strtoul(str, &end, 0); + if(end == str) + return(-1); + *ptr = end; + } + else if (('a' <= *str) && (*str <= 'h')) { + n = *str - 'a'; + str++; + *ptr = str; + } + return(n); +} + static int ubd_setup_common(char *str, int *index_out) { + struct ubd *dev; struct openflags flags = global_openflags; char *backing_file; int n, err; if(index_out) *index_out = -1; - n = *str++; + n = *str; if(n == '='){ - static int fake_major_allowed = 1; char *end; int major; + str++; + if(!strcmp(str, "mmap")){ + CHOOSE_MODE(printk("mmap not supported by the ubd " + "driver in tt mode\n"), + ubd_do_mmap = 1); + return(0); + } + if(!strcmp(str, "sync")){ global_openflags.s = 1; return(0); @@ -220,20 +274,14 @@ return(1); } - if(!fake_major_allowed){ - printk(KERN_ERR "Can't assign a fake major twice\n"); - return(1); - } - err = 1; spin_lock(&ubd_lock); - if(!fake_major_allowed){ + if(fake_major != MAJOR_NR){ printk(KERN_ERR "Can't assign a fake major twice\n"); goto out1; } fake_major = major; - fake_major_allowed = 0; printk(KERN_INFO "Setting extra ubd major number to %d\n", major); @@ -243,25 +291,23 @@ return(err); } - if(n < '0'){ - printk(KERN_ERR "ubd_setup : index out of range\n"); } - - if((n >= '0') && (n <= '9')) n -= '0'; - else if((n >= 'a') && (n <= 'z')) n -= 'a'; - else { - printk(KERN_ERR "ubd_setup : device syntax invalid\n"); + n = parse_unit(&str); + if(n < 0){ + printk(KERN_ERR "ubd_setup : couldn't parse unit number " + "'%s'\n", str); return(1); } if(n >= MAX_DEV){ - printk(KERN_ERR "ubd_setup : index out of range " - "(%d devices)\n", MAX_DEV); + printk(KERN_ERR "ubd_setup : index %d out of range " + "(%d devices)\n", n, MAX_DEV); return(1); } err = 1; spin_lock(&ubd_lock); - if(ubd_dev[n].file != NULL){ + dev = &ubd_dev[n]; + if(dev->file != NULL){ printk(KERN_ERR "ubd_setup : device already configured\n"); goto out2; } @@ -276,6 +322,11 @@ flags.s = 1; str++; } + if (*str == 'd'){ + dev->no_cow = 1; + str++; + } + if(*str++ != '='){ printk(KERN_ERR "ubd_setup : Expected '='\n"); goto out2; @@ -284,14 +335,17 @@ err = 0; backing_file = strchr(str, ','); if(backing_file){ - *backing_file = '\0'; - backing_file++; + if(dev->no_cow) + printk(KERN_ERR "Can't specify both 'd' and a " + "cow file\n"); + else { + *backing_file = '\0'; + backing_file++; + } } - ubd_dev[n].file = str; - if(ubd_is_dir(ubd_dev[n].file)) - ubd_dev[n].is_dir = 1; - ubd_dev[n].cow.file = backing_file; - ubd_dev[n].boot_openflags = flags; + dev->file = str; + dev->cow.file = backing_file; + dev->boot_openflags = flags; out2: spin_unlock(&ubd_lock); return(err); @@ -321,8 +375,7 @@ static int fakehd_set = 0; static int fakehd(char *str) { - printk(KERN_INFO - "fakehd : Changing ubd name to \"hd\".\n"); + printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n"); fakehd_set = 1; return 1; } @@ -368,32 +421,42 @@ { struct io_thread_req req; struct request *rq = elv_next_request(ubd_queue); - int n; + int n, err; do_ubd = NULL; intr_count++; n = read_ubd_fs(thread_fd, &req, sizeof(req)); if(n != sizeof(req)){ printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " - "errno = %d\n", os_getpid(), -n); + "err = %d\n", os_getpid(), -n); spin_lock(&ubd_io_lock); end_request(rq, 0); spin_unlock(&ubd_io_lock); return; } - if((req.offset != ((__u64) (rq->sector)) << 9) || - (req.length != (rq->current_nr_sectors) << 9)) + if((req.op != UBD_MMAP) && + ((req.offset != ((__u64) (rq->sector)) << 9) || + (req.length != (rq->current_nr_sectors) << 9))) panic("I/O op mismatch"); + if(req.map_fd != -1){ + err = physmem_subst_mapping(req.buffer, req.map_fd, + req.map_offset, 1); + if(err) + printk("ubd_handler - physmem_subst_mapping failed, " + "err = %d\n", -err); + } + ubd_finish(rq, req.error); reactivate_fd(thread_fd, UBD_IRQ); do_ubd_request(ubd_queue); } -static void ubd_intr(int irq, void *dev, struct pt_regs *unused) +static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused) { ubd_handler(); + return(IRQ_HANDLED); } /* Only changed by ubd_init, which is an initcall. */ @@ -429,18 +492,20 @@ static int ubd_open_dev(struct ubd *dev) { struct openflags flags; - int err, n, create_cow, *create_ptr; + char **back_ptr; + int err, create_cow, *create_ptr; + dev->openflags = dev->boot_openflags; create_cow = 0; create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL; - dev->fd = open_ubd_file(dev->file, &dev->openflags, &dev->cow.file, + back_ptr = dev->no_cow ? NULL : &dev->cow.file; + dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr, &dev->cow.bitmap_offset, &dev->cow.bitmap_len, &dev->cow.data_offset, create_ptr); if((dev->fd == -ENOENT) && create_cow){ - n = dev - ubd_dev; dev->fd = create_cow_file(dev->file, dev->cow.file, - dev->openflags, 1 << 9, + dev->openflags, 1 << 9, PAGE_SIZE, &dev->cow.bitmap_offset, &dev->cow.bitmap_len, &dev->cow.data_offset); @@ -455,13 +520,17 @@ if(dev->cow.file != NULL){ err = -ENOMEM; dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len); - if(dev->cow.bitmap == NULL) goto error; + if(dev->cow.bitmap == NULL){ + printk(KERN_ERR "Failed to vmalloc COW bitmap\n"); + goto error; + } flush_tlb_kernel_vm(); err = read_cow_bitmap(dev->fd, dev->cow.bitmap, dev->cow.bitmap_offset, dev->cow.bitmap_len); - if(err) goto error; + if(err < 0) + goto error; flags = dev->openflags; flags.w = 0; @@ -481,17 +550,31 @@ { struct gendisk *disk; + char from[sizeof("ubd/nnnnn\0")], to[sizeof("discnnnnn/disc\0")]; + int err; disk = alloc_disk(1 << UBD_SHIFT); - if (!disk) - return -ENOMEM; + if(disk == NULL) + return(-ENOMEM); disk->major = major; disk->first_minor = unit << UBD_SHIFT; disk->fops = &ubd_blops; set_capacity(disk, size / 512); - sprintf(disk->disk_name, "ubd"); - sprintf(disk->devfs_name, "ubd/disc%d", unit); + if(major == MAJOR_NR){ + sprintf(disk->disk_name, "ubd%c", 'a' + unit); + sprintf(disk->devfs_name, "ubd/disc%d", unit); + sprintf(from, "ubd/%d", unit); + sprintf(to, "disc%d/disc", unit); + err = devfs_mk_symlink(from, to); + if(err) + printk("ubd_new_disk failed to make link from %s to " + "%s, error = %d\n", from, to, err); + } + else { + sprintf(disk->disk_name, "ubd_fake%d", unit); + sprintf(disk->devfs_name, "ubd_fake/disc%d", unit); + } disk->private_data = &ubd_dev[unit]; disk->queue = ubd_queue; @@ -506,24 +589,21 @@ struct ubd *dev = &ubd_dev[n]; int err; - if(dev->is_dir) - return(-EISDIR); - - if (!dev->file) + if(dev->file == NULL) return(-ENODEV); if (ubd_open_dev(dev)) return(-ENODEV); err = ubd_file_size(dev, &dev->size); - if(err) + if(err < 0) return(err); err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]); if(err) return(err); - if(fake_major) + if(fake_major != MAJOR_NR) ubd_new_disk(fake_major, dev->size, n, &fake_gendisk[n]); @@ -561,42 +641,42 @@ return(err); } -static int ubd_get_config(char *dev, char *str, int size, char **error_out) +static int ubd_get_config(char *name, char *str, int size, char **error_out) { - struct ubd *ubd; + struct ubd *dev; char *end; - int major, n = 0; + int n, len = 0; - major = simple_strtoul(dev, &end, 0); - if((*end != '\0') || (end == dev)){ - *error_out = "ubd_get_config : didn't parse major number"; + n = simple_strtoul(name, &end, 0); + if((*end != '\0') || (end == name)){ + *error_out = "ubd_get_config : didn't parse device number"; return(-1); } - if((major >= MAX_DEV) || (major < 0)){ - *error_out = "ubd_get_config : major number out of range"; + if((n >= MAX_DEV) || (n < 0)){ + *error_out = "ubd_get_config : device number out of range"; return(-1); } - ubd = &ubd_dev[major]; + dev = &ubd_dev[n]; spin_lock(&ubd_lock); - if(ubd->file == NULL){ - CONFIG_CHUNK(str, size, n, "", 1); + if(dev->file == NULL){ + CONFIG_CHUNK(str, size, len, "", 1); goto out; } - CONFIG_CHUNK(str, size, n, ubd->file, 0); + CONFIG_CHUNK(str, size, len, dev->file, 0); - if(ubd->cow.file != NULL){ - CONFIG_CHUNK(str, size, n, ",", 0); - CONFIG_CHUNK(str, size, n, ubd->cow.file, 1); + if(dev->cow.file != NULL){ + CONFIG_CHUNK(str, size, len, ",", 0); + CONFIG_CHUNK(str, size, len, dev->cow.file, 1); } - else CONFIG_CHUNK(str, size, n, "", 1); + else CONFIG_CHUNK(str, size, len, "", 1); out: spin_unlock(&ubd_lock); - return(n); + return(len); } static int ubd_remove(char *str) @@ -604,11 +684,9 @@ struct ubd *dev; int n, err = -ENODEV; - if(!isdigit(*str)) - return(err); /* it should be a number 0-7/a-h */ + n = parse_unit(&str); - n = *str - '0'; - if(n >= MAX_DEV) + if((n < 0) || (n >= MAX_DEV)) return(err); dev = &ubd_dev[n]; @@ -669,7 +747,7 @@ elevator_init(ubd_queue, &elevator_noop); - if (fake_major != 0) { + if (fake_major != MAJOR_NR) { char name[sizeof("ubd_nnn\0")]; snprintf(name, sizeof(name), "ubd_%d", fake_major); @@ -696,6 +774,7 @@ io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), &thread_fd); if(io_pid < 0){ + io_pid = -1; printk(KERN_ERR "ubd : Failed to start I/O thread (errno = %d) - " "falling back to synchronous I/O\n", -io_pid); @@ -703,8 +782,8 @@ } err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, SA_INTERRUPT, "ubd", ubd_dev); - if(err != 0) printk(KERN_ERR - "um_request_irq failed - errno = %d\n", -err); + if(err != 0) + printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); return(err); } @@ -714,15 +793,9 @@ { struct gendisk *disk = inode->i_bdev->bd_disk; struct ubd *dev = disk->private_data; - int err = -EISDIR; - - if(dev->is_dir == 1) - goto out; + int err = 0; - err = 0; if(dev->count == 0){ - dev->openflags = dev->boot_openflags; - err = ubd_open_dev(dev); if(err){ printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n", @@ -749,62 +822,156 @@ return(0); } -void cowify_req(struct io_thread_req *req, struct ubd *dev) +static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, + __u64 *cow_offset, unsigned long *bitmap, + __u64 bitmap_offset, unsigned long *bitmap_words, + __u64 bitmap_len) +{ + __u64 sector = io_offset >> 9; + int i, update_bitmap = 0; + + for(i = 0; i < length >> 9; i++){ + if(cow_mask != NULL) + ubd_set_bit(i, (unsigned char *) cow_mask); + if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) + continue; + + update_bitmap = 1; + ubd_set_bit(sector + i, (unsigned char *) bitmap); + } + + if(!update_bitmap) + return; + + *cow_offset = sector / (sizeof(unsigned long) * 8); + + /* This takes care of the case where we're exactly at the end of the + * device, and *cow_offset + 1 is off the end. So, just back it up + * by one word. Thanks to Lynn Kerby for the fix and James McMechan + * for the original diagnosis. + */ + if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) / + sizeof(unsigned long) - 1)) + (*cow_offset)--; + + bitmap_words[0] = bitmap[*cow_offset]; + bitmap_words[1] = bitmap[*cow_offset + 1]; + + *cow_offset *= sizeof(unsigned long); + *cow_offset += bitmap_offset; +} + +static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, + __u64 bitmap_offset, __u64 bitmap_len) { - int i, update_bitmap, sector = req->offset >> 9; + __u64 sector = req->offset >> 9; + int i; if(req->length > (sizeof(req->sector_mask) * 8) << 9) panic("Operation too long"); + if(req->op == UBD_READ) { for(i = 0; i < req->length >> 9; i++){ - if(ubd_test_bit(sector + i, (unsigned char *) - dev->cow.bitmap)){ + if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) ubd_set_bit(i, (unsigned char *) &req->sector_mask); - } } - } - else { - update_bitmap = 0; - for(i = 0; i < req->length >> 9; i++){ - ubd_set_bit(i, (unsigned char *) - &req->sector_mask); - if(!ubd_test_bit(sector + i, (unsigned char *) - dev->cow.bitmap)) - update_bitmap = 1; - ubd_set_bit(sector + i, (unsigned char *) - dev->cow.bitmap); - } - if(update_bitmap){ - req->cow_offset = sector / (sizeof(unsigned long) * 8); - req->bitmap_words[0] = - dev->cow.bitmap[req->cow_offset]; - req->bitmap_words[1] = - dev->cow.bitmap[req->cow_offset + 1]; - req->cow_offset *= sizeof(unsigned long); - req->cow_offset += dev->cow.bitmap_offset; + } + else cowify_bitmap(req->offset, req->length, &req->sector_mask, + &req->cow_offset, bitmap, bitmap_offset, + req->bitmap_words, bitmap_len); +} + +static int mmap_fd(struct request *req, struct ubd *dev, __u64 offset) +{ + __u64 sector; + unsigned char *bitmap; + int bit, i; + + /* mmap must have been requested on the command line */ + if(!ubd_do_mmap) + return(-1); + + /* The buffer must be page aligned */ + if(((unsigned long) req->buffer % UBD_MMAP_BLOCK_SIZE) != 0) + return(-1); + + /* The request must be a page long */ + if((req->current_nr_sectors << 9) != PAGE_SIZE) + return(-1); + + if(dev->cow.file == NULL) + return(dev->fd); + + sector = offset >> 9; + bitmap = (unsigned char *) dev->cow.bitmap; + bit = ubd_test_bit(sector, bitmap); + + for(i = 1; i < req->current_nr_sectors; i++){ + if(ubd_test_bit(sector + i, bitmap) != bit) + return(-1); + } + + if(bit || (rq_data_dir(req) == WRITE)) + offset += dev->cow.data_offset; + + /* The data on disk must be page aligned */ + if((offset % UBD_MMAP_BLOCK_SIZE) != 0) + return(-1); + + return(bit ? dev->fd : dev->cow.fd); +} + +static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset, + struct request *req, + struct io_thread_req *io_req) +{ + int err; + + if(rq_data_dir(req) == WRITE){ + /* Writes are almost no-ops since the new data is already in the + * host page cache + */ + dev->map_writes++; + if(dev->cow.file != NULL) + cowify_bitmap(io_req->offset, io_req->length, + &io_req->sector_mask, &io_req->cow_offset, + dev->cow.bitmap, dev->cow.bitmap_offset, + io_req->bitmap_words, + dev->cow.bitmap_len); + } + else { + int w; + + if((dev->cow.file != NULL) && (fd == dev->cow.fd)) + w = 0; + else w = dev->openflags.w; + + if((dev->cow.file != NULL) && (fd == dev->fd)) + offset += dev->cow.data_offset; + + err = physmem_subst_mapping(req->buffer, fd, offset, w); + if(err){ + printk("physmem_subst_mapping failed, err = %d\n", + -err); + return(1); } + dev->map_reads++; } + io_req->op = UBD_MMAP; + io_req->buffer = req->buffer; + return(0); } static int prepare_request(struct request *req, struct io_thread_req *io_req) { struct gendisk *disk = req->rq_disk; struct ubd *dev = disk->private_data; - __u64 block; - int nsect; + __u64 offset; + int len, fd; if(req->rq_status == RQ_INACTIVE) return(1); - if(dev->is_dir){ - strcpy(req->buffer, "HOSTFS:"); - strcat(req->buffer, dev->file); - spin_lock(&ubd_io_lock); - end_request(req, 1); - spin_unlock(&ubd_io_lock); - return(1); - } - if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ printk("Write attempted on readonly ubd device %s\n", disk->disk_name); @@ -814,23 +981,49 @@ return(1); } - block = req->sector; - nsect = req->current_nr_sectors; + offset = ((__u64) req->sector) << 9; + len = req->current_nr_sectors << 9; - io_req->op = rq_data_dir(req) == READ ? UBD_READ : UBD_WRITE; io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; io_req->fds[1] = dev->fd; + io_req->map_fd = -1; + io_req->cow_offset = -1; + io_req->offset = offset; + io_req->length = len; + io_req->error = 0; + io_req->sector_mask = 0; + + fd = mmap_fd(req, dev, io_req->offset); + if(fd > 0){ + /* If mmapping is otherwise OK, but the first access to the + * page is a write, then it's not mapped in yet. So we have + * to write the data to disk first, then we can map the disk + * page in and continue normally from there. + */ + if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer)){ + io_req->map_fd = dev->fd; + io_req->map_offset = io_req->offset + + dev->cow.data_offset; + dev->write_maps++; + } + else return(prepare_mmap_request(dev, fd, io_req->offset, req, + io_req)); + } + + if(rq_data_dir(req) == READ) + dev->nomap_reads++; + else dev->nomap_writes++; + + io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE; io_req->offsets[0] = 0; io_req->offsets[1] = dev->cow.data_offset; - io_req->offset = ((__u64) block) << 9; - io_req->length = nsect << 9; io_req->buffer = req->buffer; io_req->sectorsize = 1 << 9; - io_req->sector_mask = 0; - io_req->cow_offset = -1; - io_req->error = 0; - if(dev->cow.file != NULL) cowify_req(io_req, dev); + if(dev->cow.file != NULL) + cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset, + dev->cow.bitmap_len); + return(0); } @@ -885,7 +1078,7 @@ g.heads = 128; g.sectors = 32; g.cylinders = dev->size / (128 * 32 * 512); - g.start = 2; + g.start = get_start_sect(inode->i_bdev); return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0); case HDIO_SET_UNMASKINTR: @@ -935,6 +1128,142 @@ return(-EINVAL); } +static int ubd_check_remapped(int fd, unsigned long address, int is_write, + __u64 offset) +{ + __u64 bitmap_offset; + unsigned long new_bitmap[2]; + int i, err, n; + + /* If it's not a write access, we can't do anything about it */ + if(!is_write) + return(0); + + /* We have a write */ + for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){ + struct ubd *dev = &ubd_dev[i]; + + if((dev->fd != fd) && (dev->cow.fd != fd)) + continue; + + /* It's a write to a ubd device */ + + if(!dev->openflags.w){ + /* It's a write access on a read-only device - probably + * shouldn't happen. If the kernel is trying to change + * something with no intention of writing it back out, + * then this message will clue us in that this needs + * fixing + */ + printk("Write access to mapped page from readonly ubd " + "device %d\n", i); + return(0); + } + + /* It's a write to a writeable ubd device - it must be COWed + * because, otherwise, the page would have been mapped in + * writeable + */ + + if(!dev->cow.file) + panic("Write fault on writeable non-COW ubd device %d", + i); + + /* It should also be an access to the backing file since the + * COW pages should be mapped in read-write + */ + + if(fd == dev->fd) + panic("Write fault on a backing page of ubd " + "device %d\n", i); + + /* So, we do the write, copying the backing data to the COW + * file... + */ + + err = os_seek_file(dev->fd, offset + dev->cow.data_offset); + if(err < 0) + panic("Couldn't seek to %lld in COW file of ubd " + "device %d, err = %d", + offset + dev->cow.data_offset, i, -err); + + n = os_write_file(dev->fd, (void *) address, PAGE_SIZE); + if(n != PAGE_SIZE) + panic("Couldn't copy data to COW file of ubd " + "device %d, err = %d", i, -n); + + /* ... updating the COW bitmap... */ + + cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset, + dev->cow.bitmap, dev->cow.bitmap_offset, + new_bitmap, dev->cow.bitmap_len); + + err = os_seek_file(dev->fd, bitmap_offset); + if(err < 0) + panic("Couldn't seek to %lld in COW file of ubd " + "device %d, err = %d", bitmap_offset, i, -err); + + n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap)); + if(n != sizeof(new_bitmap)) + panic("Couldn't update bitmap of ubd device %d, " + "err = %d", i, -n); + + /* Maybe we can map the COW page in, and maybe we can't. If + * it is a pre-V3 COW file, we can't, since the alignment will + * be wrong. If it is a V3 or later COW file which has been + * moved to a system with a larger page size, then maybe we + * can't, depending on the exact location of the page. + */ + + offset += dev->cow.data_offset; + + /* Remove the remapping, putting the original anonymous page + * back. If the COW file can be mapped in, that is done. + * Otherwise, the COW page is read in. + */ + + if(!physmem_remove_mapping((void *) address)) + panic("Address 0x%lx not remapped by ubd device %d", + address, i); + if((offset % UBD_MMAP_BLOCK_SIZE) == 0) + physmem_subst_mapping((void *) address, dev->fd, + offset, 1); + else { + err = os_seek_file(dev->fd, offset); + if(err < 0) + panic("Couldn't seek to %lld in COW file of " + "ubd device %d, err = %d", offset, i, + -err); + + n = os_read_file(dev->fd, (void *) address, PAGE_SIZE); + if(n != PAGE_SIZE) + panic("Failed to read page from offset %llx of " + "COW file of ubd device %d, err = %d", + offset, i, -n); + } + + return(1); + } + + /* It's not a write on a ubd device */ + return(0); +} + +static struct remapper ubd_remapper = { + .list = LIST_HEAD_INIT(ubd_remapper.list), + .proc = ubd_check_remapped, +}; + +static int ubd_remapper_setup(void) +{ + if(ubd_do_mmap) + register_remapper(&ubd_remapper); + + return(0); +} + +__initcall(ubd_remapper_setup); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically --- diff/arch/um/drivers/ubd_user.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/ubd_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -11,11 +11,8 @@ #include #include #include -#include #include -#include #include -#include #include #include #include "asm/types.h" @@ -24,146 +21,30 @@ #include "user.h" #include "ubd_user.h" #include "os.h" +#include "cow.h" #include #include -#if __BYTE_ORDER == __BIG_ENDIAN -# define ntohll(x) (x) -# define htonll(x) (x) -#elif __BYTE_ORDER == __LITTLE_ENDIAN -# define ntohll(x) bswap_64(x) -# define htonll(x) bswap_64(x) -#else -#error "__BYTE_ORDER not defined" -#endif - -#define PATH_LEN_V1 256 - -struct cow_header_v1 { - int magic; - int version; - char backing_file[PATH_LEN_V1]; - time_t mtime; - __u64 size; - int sectorsize; -}; - -#define PATH_LEN_V2 MAXPATHLEN - -struct cow_header_v2 { - unsigned long magic; - unsigned long version; - char backing_file[PATH_LEN_V2]; - time_t mtime; - __u64 size; - int sectorsize; -}; - -union cow_header { - struct cow_header_v1 v1; - struct cow_header_v2 v2; -}; - -#define COW_MAGIC 0x4f4f4f4d /* MOOO */ -#define COW_VERSION 2 - -static void sizes(__u64 size, int sectorsize, int bitmap_offset, - unsigned long *bitmap_len_out, int *data_offset_out) -{ - *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize); - - *data_offset_out = bitmap_offset + *bitmap_len_out; - *data_offset_out = (*data_offset_out + sectorsize - 1) / sectorsize; - *data_offset_out *= sectorsize; -} - -static int read_cow_header(int fd, int *magic_out, char **backing_file_out, - time_t *mtime_out, __u64 *size_out, - int *sectorsize_out, int *bitmap_offset_out) -{ - union cow_header *header; - char *file; - int err, n; - unsigned long version, magic; - - header = um_kmalloc(sizeof(*header)); - if(header == NULL){ - printk("read_cow_header - Failed to allocate header\n"); - return(-ENOMEM); - } - err = -EINVAL; - n = read(fd, header, sizeof(*header)); - if(n < offsetof(typeof(header->v1), backing_file)){ - printk("read_cow_header - short header\n"); - goto out; - } - - magic = header->v1.magic; - if(magic == COW_MAGIC) { - version = header->v1.version; - } - else if(magic == ntohl(COW_MAGIC)){ - version = ntohl(header->v1.version); - } - else goto out; - - *magic_out = COW_MAGIC; - - if(version == 1){ - if(n < sizeof(header->v1)){ - printk("read_cow_header - failed to read V1 header\n"); - goto out; - } - *mtime_out = header->v1.mtime; - *size_out = header->v1.size; - *sectorsize_out = header->v1.sectorsize; - *bitmap_offset_out = sizeof(header->v1); - file = header->v1.backing_file; - } - else if(version == 2){ - if(n < sizeof(header->v2)){ - printk("read_cow_header - failed to read V2 header\n"); - goto out; - } - *mtime_out = ntohl(header->v2.mtime); - *size_out = ntohll(header->v2.size); - *sectorsize_out = ntohl(header->v2.sectorsize); - *bitmap_offset_out = sizeof(header->v2); - file = header->v2.backing_file; - } - else { - printk("read_cow_header - invalid COW version\n"); - goto out; - } - err = -ENOMEM; - *backing_file_out = uml_strdup(file); - if(*backing_file_out == NULL){ - printk("read_cow_header - failed to allocate backing file\n"); - goto out; - } - err = 0; - out: - kfree(header); - return(err); -} static int same_backing_files(char *from_cmdline, char *from_cow, char *cow) { - struct stat buf1, buf2; + struct uml_stat buf1, buf2; + int err; if(from_cmdline == NULL) return(1); if(!strcmp(from_cmdline, from_cow)) return(1); - if(stat(from_cmdline, &buf1) < 0){ - printk("Couldn't stat '%s', errno = %d\n", from_cmdline, - errno); + err = os_stat_file(from_cmdline, &buf1); + if(err < 0){ + printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err); return(1); } - if(stat(from_cow, &buf2) < 0){ - printk("Couldn't stat '%s', errno = %d\n", from_cow, errno); + err = os_stat_file(from_cow, &buf2); + if(err < 0){ + printk("Couldn't stat '%s', err = %d\n", from_cow, -err); return(1); } - if((buf1.st_dev == buf2.st_dev) && (buf1.st_ino == buf2.st_ino)) + if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) return(1); printk("Backing file mismatch - \"%s\" requested,\n" @@ -174,20 +55,21 @@ static int backing_file_mismatch(char *file, __u64 size, time_t mtime) { - struct stat64 buf; + unsigned long modtime; long long actual; int err; - if(stat64(file, &buf) < 0){ - printk("Failed to stat backing file \"%s\", errno = %d\n", - file, errno); - return(-errno); + err = os_file_modtime(file, &modtime); + if(err < 0){ + printk("Failed to get modification time of backing file " + "\"%s\", err = %d\n", file, -err); + return(err); } err = os_file_size(file, &actual); - if(err){ + if(err < 0){ printk("Failed to get size of backing file \"%s\", " - "errno = %d\n", file, -err); + "err = %d\n", file, -err); return(err); } @@ -196,9 +78,9 @@ "file\n", size, actual); return(-EINVAL); } - if(buf.st_mtime != mtime){ + if(modtime != mtime){ printk("mtime mismatch (%ld vs %ld) of COW header vs backing " - "file\n", mtime, buf.st_mtime); + "file\n", mtime, modtime); return(-EINVAL); } return(0); @@ -209,124 +91,16 @@ int err; err = os_seek_file(fd, offset); - if(err != 0) return(-errno); - err = read(fd, buf, len); - if(err < 0) return(-errno); - return(0); -} + if(err < 0) + return(err); -static int absolutize(char *to, int size, char *from) -{ - char save_cwd[256], *slash; - int remaining; + err = os_read_file(fd, buf, len); + if(err < 0) + return(err); - if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) { - printk("absolutize : unable to get cwd - errno = %d\n", errno); - return(-1); - } - slash = strrchr(from, '/'); - if(slash != NULL){ - *slash = '\0'; - if(chdir(from)){ - *slash = '/'; - printk("absolutize : Can't cd to '%s' - errno = %d\n", - from, errno); - return(-1); - } - *slash = '/'; - if(getcwd(to, size) == NULL){ - printk("absolutize : unable to get cwd of '%s' - " - "errno = %d\n", from, errno); - return(-1); - } - remaining = size - strlen(to); - if(strlen(slash) + 1 > remaining){ - printk("absolutize : unable to fit '%s' into %d " - "chars\n", from, size); - return(-1); - } - strcat(to, slash); - } - else { - if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){ - printk("absolutize : unable to fit '%s' into %d " - "chars\n", from, size); - return(-1); - } - strcpy(to, save_cwd); - strcat(to, "/"); - strcat(to, from); - } - chdir(save_cwd); return(0); } -static int write_cow_header(char *cow_file, int fd, char *backing_file, - int sectorsize, long long *size) -{ - struct cow_header_v2 *header; - struct stat64 buf; - int err; - - err = os_seek_file(fd, 0); - if(err != 0){ - printk("write_cow_header - lseek failed, errno = %d\n", errno); - return(-errno); - } - - err = -ENOMEM; - header = um_kmalloc(sizeof(*header)); - if(header == NULL){ - printk("Failed to allocate COW V2 header\n"); - goto out; - } - header->magic = htonl(COW_MAGIC); - header->version = htonl(COW_VERSION); - - err = -EINVAL; - if(strlen(backing_file) > sizeof(header->backing_file) - 1){ - printk("Backing file name \"%s\" is too long - names are " - "limited to %d characters\n", backing_file, - sizeof(header->backing_file) - 1); - goto out_free; - } - - if(absolutize(header->backing_file, sizeof(header->backing_file), - backing_file)) - goto out_free; - - err = stat64(header->backing_file, &buf); - if(err < 0){ - printk("Stat of backing file '%s' failed, errno = %d\n", - header->backing_file, errno); - err = -errno; - goto out_free; - } - - err = os_file_size(header->backing_file, size); - if(err){ - printk("Couldn't get size of backing file '%s', errno = %d\n", - header->backing_file, -*size); - goto out_free; - } - - header->mtime = htonl(buf.st_mtime); - header->size = htonll(*size); - header->sectorsize = htonl(sectorsize); - - err = write(fd, header, sizeof(*header)); - if(err != sizeof(*header)){ - printk("Write of header to new COW file '%s' failed, " - "errno = %d\n", cow_file, errno); - goto out_free; - } - err = 0; - out_free: - kfree(header); - out: - return(err); -} - int open_ubd_file(char *file, struct openflags *openflags, char **backing_file_out, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out, @@ -334,26 +108,36 @@ { time_t mtime; __u64 size; + __u32 version, align; char *backing_file; - int fd, err, sectorsize, magic, same, mode = 0644; + int fd, err, sectorsize, same, mode = 0644; - if((fd = os_open_file(file, *openflags, mode)) < 0){ + fd = os_open_file(file, *openflags, mode); + if(fd < 0){ if((fd == -ENOENT) && (create_cow_out != NULL)) *create_cow_out = 1; if(!openflags->w || ((errno != EROFS) && (errno != EACCES))) return(-errno); openflags->w = 0; - if((fd = os_open_file(file, *openflags, mode)) < 0) + fd = os_open_file(file, *openflags, mode); + if(fd < 0) return(fd); } + + err = os_lock_file(fd, openflags->w); + if(err < 0){ + printk("Failed to lock '%s', err = %d\n", file, -err); + goto out_close; + } + if(backing_file_out == NULL) return(fd); - err = read_cow_header(fd, &magic, &backing_file, &mtime, &size, - §orsize, bitmap_offset_out); + err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, + &size, §orsize, &align, bitmap_offset_out); if(err && (*backing_file_out != NULL)){ printk("Failed to read COW header from COW file \"%s\", " - "errno = %d\n", file, err); - goto error; + "errno = %d\n", file, -err); + goto out_close; } if(err) return(fd); @@ -363,36 +147,33 @@ if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){ printk("Switching backing file to '%s'\n", *backing_file_out); - err = write_cow_header(file, fd, *backing_file_out, - sectorsize, &size); + err = write_cow_header(file, fd, *backing_file_out, + sectorsize, align, &size); if(err){ - printk("Switch failed, errno = %d\n", err); + printk("Switch failed, errno = %d\n", -err); return(err); } } else { *backing_file_out = backing_file; err = backing_file_mismatch(*backing_file_out, size, mtime); - if(err) goto error; + if(err) goto out_close; } - sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out, - data_offset_out); + cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, + bitmap_len_out, data_offset_out); return(fd); - error: - close(fd); + out_close: + os_close_file(fd); return(err); } int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, - int sectorsize, int *bitmap_offset_out, + int sectorsize, int alignment, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out) { - __u64 blocks; - long zero; - int err, fd, i; - long long size; + int err, fd; flags.c = 1; fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL); @@ -403,57 +184,49 @@ goto out; } - err = write_cow_header(cow_file, fd, backing_file, sectorsize, &size); - if(err) goto out_close; - - blocks = (size + sectorsize - 1) / sectorsize; - blocks = (blocks + sizeof(long) * 8 - 1) / (sizeof(long) * 8); - zero = 0; - for(i = 0; i < blocks; i++){ - err = write(fd, &zero, sizeof(zero)); - if(err != sizeof(zero)){ - printk("Write of bitmap to new COW file '%s' failed, " - "errno = %d\n", cow_file, errno); - goto out_close; - } - } - - sizes(size, sectorsize, sizeof(struct cow_header_v2), - bitmap_len_out, data_offset_out); - *bitmap_offset_out = sizeof(struct cow_header_v2); - - return(fd); - - out_close: - close(fd); + err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment, + bitmap_offset_out, bitmap_len_out, + data_offset_out); + if(!err) + return(fd); + os_close_file(fd); out: return(err); } +/* XXX Just trivial wrappers around os_read_file and os_write_file */ int read_ubd_fs(int fd, void *buffer, int len) { - int n; - - n = read(fd, buffer, len); - if(n < 0) return(-errno); - else return(n); + return(os_read_file(fd, buffer, len)); } int write_ubd_fs(int fd, char *buffer, int len) { - int n; - - n = write(fd, buffer, len); - if(n < 0) return(-errno); - else return(n); + return(os_write_file(fd, buffer, len)); } -int ubd_is_dir(char *file) +static int update_bitmap(struct io_thread_req *req) { - struct stat64 buf; + int n; + + if(req->cow_offset == -1) + return(0); + + n = os_seek_file(req->fds[1], req->cow_offset); + if(n < 0){ + printk("do_io - bitmap lseek failed : err = %d\n", -n); + return(1); + } + + n = os_write_file(req->fds[1], &req->bitmap_words, + sizeof(req->bitmap_words)); + if(n != sizeof(req->bitmap_words)){ + printk("do_io - bitmap update failed, err = %d fd = %d\n", -n, + req->fds[1]); + return(1); + } - if(stat64(file, &buf) < 0) return(0); - return(S_ISDIR(buf.st_mode)); + return(0); } void do_io(struct io_thread_req *req) @@ -461,8 +234,18 @@ char *buf; unsigned long len; int n, nsectors, start, end, bit; + int err; __u64 off; + if(req->op == UBD_MMAP){ + /* Touch the page to force the host to do any necessary IO to + * get it into memory + */ + n = *((volatile int *) req->buffer); + req->error = update_bitmap(req); + return; + } + nsectors = req->length / req->sectorsize; start = 0; do { @@ -473,15 +256,14 @@ &req->sector_mask) == bit)) end++; - if(end != nsectors) - printk("end != nsectors\n"); off = req->offset + req->offsets[bit] + start * req->sectorsize; len = (end - start) * req->sectorsize; buf = &req->buffer[start * req->sectorsize]; - if(os_seek_file(req->fds[bit], off) != 0){ - printk("do_io - lseek failed : errno = %d\n", errno); + err = os_seek_file(req->fds[bit], off); + if(err < 0){ + printk("do_io - lseek failed : err = %d\n", -err); req->error = 1; return; } @@ -490,11 +272,10 @@ do { buf = &buf[n]; len -= n; - n = read(req->fds[bit], buf, len); + n = os_read_file(req->fds[bit], buf, len); if (n < 0) { - printk("do_io - read returned %d : " - "errno = %d fd = %d\n", n, - errno, req->fds[bit]); + printk("do_io - read failed, err = %d " + "fd = %d\n", -n, req->fds[bit]); req->error = 1; return; } @@ -502,11 +283,10 @@ if (n < len) memset(&buf[n], 0, len - n); } else { - n = write(req->fds[bit], buf, len); + n = os_write_file(req->fds[bit], buf, len); if(n != len){ - printk("do_io - write returned %d : " - "errno = %d fd = %d\n", n, - errno, req->fds[bit]); + printk("do_io - write failed err = %d " + "fd = %d\n", -n, req->fds[bit]); req->error = 1; return; } @@ -515,24 +295,7 @@ start = end; } while(start < nsectors); - if(req->cow_offset != -1){ - if(os_seek_file(req->fds[1], req->cow_offset) != 0){ - printk("do_io - bitmap lseek failed : errno = %d\n", - errno); - req->error = 1; - return; - } - n = write(req->fds[1], &req->bitmap_words, - sizeof(req->bitmap_words)); - if(n != sizeof(req->bitmap_words)){ - printk("do_io - bitmap update returned %d : " - "errno = %d fd = %d\n", n, errno, req->fds[1]); - req->error = 1; - return; - } - } - req->error = 0; - return; + req->error = update_bitmap(req); } /* Changed in start_io_thread, which is serialized by being called only @@ -550,19 +313,23 @@ signal(SIGWINCH, SIG_IGN); while(1){ - n = read(kernel_fd, &req, sizeof(req)); - if(n < 0) printk("io_thread - read returned %d, errno = %d\n", - n, errno); - else if(n < sizeof(req)){ - printk("io_thread - short read : length = %d\n", n); + n = os_read_file(kernel_fd, &req, sizeof(req)); + if(n != sizeof(req)){ + if(n < 0) + printk("io_thread - read failed, fd = %d, " + "err = %d\n", kernel_fd, -n); + else { + printk("io_thread - short read, fd = %d, " + "length = %d\n", kernel_fd, n); + } continue; } io_count++; do_io(&req); - n = write(kernel_fd, &req, sizeof(req)); + n = os_write_file(kernel_fd, &req, sizeof(req)); if(n != sizeof(req)) - printk("io_thread - write failed, errno = %d\n", - errno); + printk("io_thread - write failed, fd = %d, err = %d\n", + kernel_fd, -n); } } @@ -571,10 +338,11 @@ int pid, fds[2], err; err = os_pipe(fds, 1, 1); - if(err){ - printk("start_io_thread - os_pipe failed, errno = %d\n", -err); - return(-1); + if(err < 0){ + printk("start_io_thread - os_pipe failed, err = %d\n", -err); + goto out; } + kernel_fd = fds[0]; *fd_out = fds[1]; @@ -582,32 +350,19 @@ NULL); if(pid < 0){ printk("start_io_thread - clone failed : errno = %d\n", errno); - return(-errno); + goto out_close; } - return(pid); -} - -#ifdef notdef -int start_io_thread(unsigned long sp, int *fd_out) -{ - int pid; - if((kernel_fd = get_pty()) < 0) return(-1); - raw(kernel_fd, 0); - if((*fd_out = open(ptsname(kernel_fd), O_RDWR)) < 0){ - printk("Couldn't open tty for IO\n"); - return(-1); - } - - pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD, - NULL); - if(pid < 0){ - printk("start_io_thread - clone failed : errno = %d\n", errno); - return(-errno); - } return(pid); + + out_close: + os_close_file(fds[0]); + os_close_file(fds[1]); + kernel_fd = -1; + *fd_out = -1; + out: + return(err); } -#endif /* * Overrides for Emacs so that we follow Linus's tabbing style. --- diff/arch/um/drivers/xterm.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/xterm.c 2004-02-09 10:39:51.000000000 +0000 @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -36,7 +35,8 @@ { struct xterm_chan *data; - if((data = malloc(sizeof(*data))) == NULL) return(NULL); + data = malloc(sizeof(*data)); + if(data == NULL) return(NULL); *data = ((struct xterm_chan) { .pid = -1, .helper_pid = -1, .device = device, @@ -93,7 +93,7 @@ "/usr/lib/uml/port-helper", "-uml-socket", file, NULL }; - if(access(argv[4], X_OK)) + if(os_access(argv[4], OS_ACC_X_OK) < 0) argv[4] = "port-helper"; fd = mkstemp(file); @@ -106,13 +106,13 @@ printk("xterm_open : unlink failed, errno = %d\n", errno); return(-errno); } - close(fd); + os_close_file(fd); - fd = create_unix_socket(file, sizeof(file)); + fd = os_create_unix_socket(file, sizeof(file), 1); if(fd < 0){ printk("xterm_open : create_unix_socket failed, errno = %d\n", -fd); - return(-fd); + return(fd); } sprintf(title, data->title, data->device); @@ -128,15 +128,16 @@ if(data->direct_rcv) new = os_rcv_fd(fd, &data->helper_pid); else { - if((err = os_set_fd_block(fd, 0)) != 0){ + err = os_set_fd_block(fd, 0); + if(err < 0){ printk("xterm_open : failed to set descriptor " - "non-blocking, errno = %d\n", err); + "non-blocking, err = %d\n", -err); return(err); } new = xterm_fd(fd, &data->helper_pid); } if(new < 0){ - printk("xterm_open : os_rcv_fd failed, errno = %d\n", -new); + printk("xterm_open : os_rcv_fd failed, err = %d\n", -new); goto out; } @@ -160,7 +161,7 @@ if(data->helper_pid != -1) os_kill_process(data->helper_pid, 0); data->helper_pid = -1; - close(fd); + os_close_file(fd); } void xterm_free(void *d) --- diff/arch/um/drivers/xterm_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/drivers/xterm_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -5,9 +5,12 @@ #include "linux/errno.h" #include "linux/slab.h" +#include "linux/signal.h" +#include "linux/interrupt.h" #include "asm/semaphore.h" #include "asm/irq.h" #include "irq_user.h" +#include "irq_kern.h" #include "kern_util.h" #include "os.h" #include "xterm.h" @@ -19,17 +22,18 @@ int new_fd; }; -static void xterm_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t xterm_interrupt(int irq, void *data, struct pt_regs *regs) { struct xterm_wait *xterm = data; int fd; fd = os_rcv_fd(xterm->fd, &xterm->pid); if(fd == -EAGAIN) - return; + return(IRQ_NONE); xterm->new_fd = fd; up(&xterm->sem); + return(IRQ_HANDLED); } int xterm_fd(int socket, int *pid_out) @@ -54,7 +58,8 @@ if(err){ printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, " "err = %d\n", err); - return(err); + ret = err; + goto out; } down(&data->sem); @@ -62,6 +67,7 @@ ret = data->new_fd; *pid_out = data->pid; + out: kfree(data); return(ret); --- diff/arch/um/dyn.lds.S 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/dyn.lds.S 2004-02-09 10:39:51.000000000 +0000 @@ -10,12 +10,15 @@ { . = START + SIZEOF_HEADERS; .interp : { *(.interp) } - . = ALIGN(4096); __binary_start = .; . = ALIGN(4096); /* Init code and data */ _stext = .; __init_begin = .; - .text.init : { *(.text.init) } + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } . = ALIGN(4096); @@ -67,7 +70,7 @@ #include "asm/common.lds.S" - .data.init : { *(.data.init) } + init.data : { *(.init.data) } /* Ensure the __preinit_array_start label is properly aligned. We could instead move the label definition inside the section, but --- diff/arch/um/include/2_5compat.h 2002-10-16 04:28:20.000000000 +0100 +++ source/arch/um/include/2_5compat.h 2004-02-09 10:39:51.000000000 +0000 @@ -6,20 +6,6 @@ #ifndef __2_5_COMPAT_H__ #define __2_5_COMPAT_H__ -#include "linux/version.h" - -#define INIT_CONSOLE(dev_name, write_proc, device_proc, setup_proc, f) { \ - name : dev_name, \ - write : write_proc, \ - read : NULL, \ - device : device_proc, \ - setup : setup_proc, \ - flags : f, \ - index : -1, \ - cflag : 0, \ - next : NULL \ -} - #define INIT_HARDSECT(arr, maj, sizes) #define SET_PRI(task) do ; while(0) --- diff/arch/um/include/kern_util.h 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/include/kern_util.h 2004-02-09 10:39:51.000000000 +0000 @@ -63,10 +63,9 @@ extern void *syscall_sp(void *t); extern void syscall_trace(void); extern int hz(void); -extern void idle_timer(void); +extern void uml_idle_timer(void); extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs); extern int external_pid(void *t); -extern int pid_to_processor_id(int pid); extern void boot_timer_handler(int sig); extern void interrupt_end(void); extern void initial_thread_cb(void (*proc)(void *), void *arg); @@ -90,9 +89,7 @@ extern char *uml_strdup(char *string); extern void unprotect_kernel_mem(void); extern void protect_kernel_mem(void); -extern void set_kmem_end(unsigned long); extern void uml_cleanup(void); -extern int pid_to_processor_id(int pid); extern void set_current(void *t); extern void lock_signalled_task(void *t); extern void IPI_handler(int cpu); @@ -101,7 +98,9 @@ extern int clear_user_proc(void *buf, int size); extern int copy_to_user_proc(void *to, void *from, int size); extern int copy_from_user_proc(void *to, void *from, int size); +extern int strlen_user_proc(char *str); extern void bus_handler(int sig, union uml_pt_regs *regs); +extern void winch(int sig, union uml_pt_regs *regs); extern long execute_syscall(void *r); extern int smp_sigio_handler(void); extern void *get_current(void); @@ -112,6 +111,8 @@ extern void free_irq(unsigned int, void *); extern int um_in_interrupt(void); extern int cpu(void); +extern unsigned long long time_stamp(void); + #endif /* --- diff/arch/um/include/line.h 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/include/line.h 2004-02-09 10:39:51.000000000 +0000 @@ -9,12 +9,14 @@ #include "linux/list.h" #include "linux/workqueue.h" #include "linux/tty.h" +#include "linux/interrupt.h" #include "asm/semaphore.h" #include "chan_user.h" #include "mconsole_kern.h" struct line_driver { char *name; + char *device_name; char *devfs_name; short major; short minor_start; @@ -67,8 +69,6 @@ #define LINES_INIT(n) { num : n } -extern void line_interrupt(int irq, void *data, struct pt_regs *unused); -extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused); extern void line_close(struct line *lines, struct tty_struct *tty); extern int line_open(struct line *lines, struct tty_struct *tty, struct chan_opts *opts); --- diff/arch/um/include/mconsole.h 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/include/mconsole.h 2004-02-09 10:39:51.000000000 +0000 @@ -41,11 +41,13 @@ struct mc_request; +enum mc_context { MCONSOLE_INTR, MCONSOLE_PROC }; + struct mconsole_command { char *command; void (*handler)(struct mc_request *req); - int as_interrupt; + enum mc_context context; }; struct mc_request @@ -77,6 +79,8 @@ extern void mconsole_cad(struct mc_request *req); extern void mconsole_stop(struct mc_request *req); extern void mconsole_go(struct mc_request *req); +extern void mconsole_log(struct mc_request *req); +extern void mconsole_proc(struct mc_request *req); extern int mconsole_get_request(int fd, struct mc_request *req); extern int mconsole_notify(char *sock_name, int type, const void *data, --- diff/arch/um/include/mem.h 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/include/mem.h 2004-02-09 10:39:51.000000000 +0000 @@ -1,19 +1,17 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002, 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ #ifndef __MEM_H__ #define __MEM_H__ -struct vm_reserved { - struct list_head list; - unsigned long start; - unsigned long end; -}; +#include "linux/types.h" -extern void set_usable_vm(unsigned long start, unsigned long end); -extern void set_kmem_end(unsigned long new); +extern int phys_mapping(unsigned long phys, __u64 *offset_out); +extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w); +extern int is_remapped(void *virt); +extern int physmem_remove_mapping(void *virt); #endif --- diff/arch/um/include/mem_user.h 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/include/mem_user.h 2004-02-09 10:39:51.000000000 +0000 @@ -32,43 +32,38 @@ #ifndef _MEM_USER_H #define _MEM_USER_H -struct mem_region { +struct iomem_region { + struct iomem_region *next; char *driver; - unsigned long start_pfn; - unsigned long start; - unsigned long len; - void *mem_map; int fd; + int size; + unsigned long phys; + unsigned long virt; }; -extern struct mem_region *regions[]; -extern struct mem_region physmem_region; +extern struct iomem_region *iomem_regions; +extern int iomem_size; #define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1)) extern unsigned long host_task_size; extern unsigned long task_size; +extern void check_devanon(void); extern int init_mem_user(void); extern int create_mem_file(unsigned long len); -extern void setup_range(int fd, char *driver, unsigned long start, - unsigned long pfn, unsigned long total, int need_vm, - struct mem_region *region, void *reserved); extern void setup_memory(void *entry); extern unsigned long find_iomem(char *driver, unsigned long *len_out); -extern int init_maps(struct mem_region *region); -extern int nregions(void); -extern int reserve_vm(unsigned long start, unsigned long end, void *e); +extern int init_maps(unsigned long physmem, unsigned long iomem, + unsigned long highmem); extern unsigned long get_vm(unsigned long len); extern void setup_physmem(unsigned long start, unsigned long usable, - unsigned long len); -extern int setup_region(struct mem_region *region, void *entry); + unsigned long len, unsigned long highmem); extern void add_iomem(char *name, int fd, unsigned long size); -extern struct mem_region *phys_region(unsigned long phys); extern unsigned long phys_offset(unsigned long phys); extern void unmap_physmem(void); -extern int map_memory(unsigned long virt, unsigned long phys, - unsigned long len, int r, int w, int x); +extern void map_memory(unsigned long virt, unsigned long phys, + unsigned long len, int r, int w, int x); extern int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, int must_succeed); extern unsigned long get_kmem_end(void); --- diff/arch/um/include/os.h 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/include/os.h 2004-02-09 10:39:51.000000000 +0000 @@ -17,6 +17,32 @@ #define OS_TYPE_FIFO 6 #define OS_TYPE_SOCK 7 +/* os_access() flags */ +#define OS_ACC_F_OK 0 /* Test for existence. */ +#define OS_ACC_X_OK 1 /* Test for execute permission. */ +#define OS_ACC_W_OK 2 /* Test for write permission. */ +#define OS_ACC_R_OK 4 /* Test for read permission. */ +#define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */ + +/* + * types taken from stat_file() in hostfs_user.c + * (if they are wrong here, they are wrong there...). + */ +struct uml_stat { + int ust_dev; /* device */ + unsigned long long ust_ino; /* inode */ + int ust_mode; /* protection */ + int ust_nlink; /* number of hard links */ + int ust_uid; /* user ID of owner */ + int ust_gid; /* group ID of owner */ + unsigned long long ust_size; /* total size, in bytes */ + int ust_blksize; /* blocksize for filesystem I/O */ + unsigned long long ust_blocks; /* number of blocks allocated */ + unsigned long ust_atime; /* time of last access */ + unsigned long ust_mtime; /* time of last modification */ + unsigned long ust_ctime; /* time of last change */ +}; + struct openflags { unsigned int r : 1; unsigned int w : 1; @@ -84,29 +110,47 @@ flags.e = 1; return(flags); } - + static inline struct openflags of_cloexec(struct openflags flags) { flags.cl = 1; return(flags); } +extern int os_stat_file(const char *file_name, struct uml_stat *buf); +extern int os_stat_fd(const int fd, struct uml_stat *buf); +extern int os_access(const char *file, int mode); +extern void os_print_error(int error, const char* str); +extern int os_get_exec_close(int fd, int *close_on_exec); +extern int os_set_exec_close(int fd, int close_on_exec); +extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg); +extern int os_window_size(int fd, int *rows, int *cols); +extern int os_new_tty_pgrp(int fd, int pid); +extern int os_get_ifname(int fd, char *namebuf); +extern int os_set_slip(int fd); +extern int os_set_owner(int fd, int pid); +extern int os_sigio_async(int master, int slave); +extern int os_mode_fd(int fd, int mode); + extern int os_seek_file(int fd, __u64 offset); extern int os_open_file(char *file, struct openflags flags, int mode); extern int os_read_file(int fd, void *buf, int len); -extern int os_write_file(int fd, void *buf, int count); +extern int os_write_file(int fd, const void *buf, int count); extern int os_file_size(char *file, long long *size_out); +extern int os_file_modtime(char *file, unsigned long *modtime); extern int os_pipe(int *fd, int stream, int close_on_exec); extern int os_set_fd_async(int fd, int owner); extern int os_set_fd_block(int fd, int blocking); extern int os_accept_connection(int fd); +extern int os_create_unix_socket(char *file, int len, int close_on_exec); extern int os_shutdown_socket(int fd, int r, int w); extern void os_close_file(int fd); extern int os_rcv_fd(int fd, int *helper_pid_out); -extern int create_unix_socket(char *file, int len); +extern int create_unix_socket(char *file, int len, int close_on_exec); extern int os_connect_socket(char *name); extern int os_file_type(char *file); extern int os_file_mode(char *file, struct openflags *mode_out); +extern int os_lock_file(int fd, int excl); extern unsigned long os_process_pc(int pid); extern int os_process_parent(int pid); @@ -115,11 +159,12 @@ extern void os_usr1_process(int pid); extern int os_getpid(void); -extern int os_map_memory(void *virt, int fd, unsigned long off, +extern int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, int r, int w, int x); extern int os_protect_memory(void *addr, unsigned long len, int r, int w, int x); extern int os_unmap_memory(void *addr, int len); +extern void os_flush_stdout(void); #endif --- diff/arch/um/include/skas_ptrace.h 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/include/skas_ptrace.h 2004-02-09 10:39:51.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ --- diff/arch/um/include/sysdep-i386/frame_user.h 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/include/sysdep-i386/frame_user.h 2004-02-09 10:39:51.000000000 +0000 @@ -56,26 +56,26 @@ * it would have to be __builtin_frame_address(1). */ -static inline unsigned long frame_restorer(void) -{ - unsigned long *fp; - - fp = __builtin_frame_address(0); - return((unsigned long) (fp + 1)); -} +#define frame_restorer() \ +({ \ + unsigned long *fp; \ +\ + fp = __builtin_frame_address(0); \ + ((unsigned long) (fp + 1)); \ +}) /* Similarly, this returns the value of sp when the handler was first * entered. This is used to calculate the proper sp when delivering * signals. */ -static inline unsigned long frame_sp(void) -{ - unsigned long *fp; - - fp = __builtin_frame_address(0); - return((unsigned long) (fp + 1)); -} +#define frame_sp() \ +({ \ + unsigned long *fp; \ +\ + fp = __builtin_frame_address(0); \ + ((unsigned long) (fp + 1)); \ +}) #endif --- diff/arch/um/include/sysdep-i386/sigcontext.h 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/include/sysdep-i386/sigcontext.h 2004-02-09 10:39:51.000000000 +0000 @@ -28,8 +28,8 @@ */ #define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0) -/* These are General Protection and Page Fault */ -#define SEGV_IS_FIXABLE(trap) ((trap == 13) || (trap == 14)) +/* This is Page Fault */ +#define SEGV_IS_FIXABLE(trap) (trap == 14) #define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc))) --- diff/arch/um/include/ubd_user.h 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/include/ubd_user.h 2004-02-09 10:39:51.000000000 +0000 @@ -9,7 +9,7 @@ #include "os.h" -enum ubd_req { UBD_READ, UBD_WRITE }; +enum ubd_req { UBD_READ, UBD_WRITE, UBD_MMAP }; struct io_thread_req { enum ubd_req op; @@ -20,8 +20,10 @@ char *buffer; int sectorsize; unsigned long sector_mask; - unsigned long cow_offset; + unsigned long long cow_offset; unsigned long bitmap_words[2]; + int map_fd; + unsigned long long map_offset; int error; }; @@ -31,7 +33,7 @@ int *create_cow_out); extern int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, int sectorsize, - int *bitmap_offset_out, + int alignment, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out); extern int read_cow_bitmap(int fd, void *buf, int offset, int len); @@ -39,7 +41,6 @@ extern int write_ubd_fs(int fd, char *buffer, int len); extern int start_io_thread(unsigned long sp, int *fds_out); extern void do_io(struct io_thread_req *req); -extern int ubd_is_dir(char *file); static inline int ubd_test_bit(__u64 bit, unsigned char *data) { --- diff/arch/um/include/um_uaccess.h 2003-01-02 10:43:04.000000000 +0000 +++ source/arch/um/include/um_uaccess.h 2004-02-09 10:39:51.000000000 +0000 @@ -38,22 +38,73 @@ from, n)); } +/* + * strncpy_from_user: - Copy a NUL terminated string from userspace. + * @dst: Destination address, in kernel space. This buffer must be at + * least @count bytes long. + * @src: Source address, in user space. + * @count: Maximum number of bytes to copy, including the trailing NUL. + * + * Copies a NUL-terminated string from userspace to kernel space. + * + * On success, returns the length of the string (not including the trailing + * NUL). + * + * If access to userspace fails, returns -EFAULT (some data may have been + * copied). + * + * If @count is smaller than the length of the string, copies @count bytes + * and returns @count. + */ + static inline int strncpy_from_user(char *dst, const char *src, int count) { return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas, dst, src, count)); } +/* + * __clear_user: - Zero a block of memory in user space, with less checking. + * @to: Destination address, in user space. + * @n: Number of bytes to zero. + * + * Zero a block of memory in user space. Caller must check + * the specified block with access_ok() before calling this function. + * + * Returns number of bytes that could not be cleared. + * On success, this will be zero. + */ static inline int __clear_user(void *mem, int len) { return(CHOOSE_MODE_PROC(__clear_user_tt, __clear_user_skas, mem, len)); } +/* + * clear_user: - Zero a block of memory in user space. + * @to: Destination address, in user space. + * @n: Number of bytes to zero. + * + * Zero a block of memory in user space. + * + * Returns number of bytes that could not be cleared. + * On success, this will be zero. + */ static inline int clear_user(void *mem, int len) { return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len)); } +/* + * strlen_user: - Get the size of a string in user space. + * @str: The string to measure. + * @n: The maximum valid length + * + * Get the size of a NUL-terminated string in user space. + * + * Returns the size of the string INCLUDING the terminating NUL. + * On exception, returns 0. + * If the string is too long, returns a value greater than @n. + */ static inline int strnlen_user(const void *str, int len) { return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len)); --- diff/arch/um/include/user.h 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/include/user.h 2004-02-09 10:39:51.000000000 +0000 @@ -14,6 +14,7 @@ extern void kfree(void *ptr); extern int in_aton(char *str); extern int open_gdb_chan(void); +extern int strlcpy(char *, const char *, int); #endif --- diff/arch/um/include/user_util.h 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/include/user_util.h 2004-02-09 10:39:51.000000000 +0000 @@ -14,8 +14,6 @@ extern int unlockpt(int __fd); extern char *ptsname(int __fd); -enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; - struct cpu_task { int pid; void *task; @@ -59,7 +57,6 @@ extern void *add_signal_handler(int sig, void (*handler)(int)); extern int start_fork_tramp(void *arg, unsigned long temp_stack, int clone_flags, int (*tramp)(void *)); -extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags); extern int linux_main(int argc, char **argv); extern void set_cmdline(char *cmd); extern void input_cb(void (*proc)(void *), void *arg, int arg_len); @@ -86,11 +83,13 @@ extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); extern void write_sigio_workaround(void); extern void arch_check_bugs(void); +extern int cpu_feature(char *what, char *buf, int len); extern int arch_handle_signal(int sig, union uml_pt_regs *regs); extern int arch_fixup(unsigned long address, void *sc_ptr); extern void forward_pending_sigio(int target); extern int can_do_skas(void); - +extern void arch_init_thread(void); + #endif /* --- diff/arch/um/kernel/Makefile 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -7,11 +7,11 @@ obj-y = checksum.o config.o exec_kern.o exitcode.o frame_kern.o frame.o \ helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \ - process.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \ - sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o \ - syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o \ - time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \ - umid.o user_syms.o user_util.o + physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \ + sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \ + syscall_kern.o syscall_user.o sysrq.o sys_call_table.o tempfile.o \ + time.o time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o \ + um_arch.o umid.o user_syms.o user_util.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o obj-$(CONFIG_GPROF) += gprof_syms.o @@ -21,6 +21,8 @@ obj-$(CONFIG_MODE_TT) += tt/ obj-$(CONFIG_MODE_SKAS) += skas/ +clean-files := config.c + user-objs-$(CONFIG_TTY_LOG) += tty_log.o USER_OBJS := $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o \ @@ -45,17 +47,13 @@ $(obj)/frame.o: $(src)/frame.c $(CC) $(CFLAGS_$(notdir $@)) -c -o $@ $< -QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while() { $$_ =~ s/CONFIG/$$config/; print $$_ }' +QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; $$config =~ s/\n/\\n"\n"/g ; while() { $$_ =~ s/CONFIG/$$config/; print $$_ }' $(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config $(PERL) -e $(QUOTE) < $(src)/config.c.in > $@ $(obj)/config.o : $(obj)/config.c -clean: - rm -f config.c - for dir in $(subdir-y) ; do $(MAKE) -C $$dir clean; done - modules: fastdep: --- diff/arch/um/kernel/config.c.in 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/config.c.in 2004-02-09 10:39:51.000000000 +0000 @@ -7,9 +7,7 @@ #include #include "init.h" -static __initdata char *config = " -CONFIG -"; +static __initdata char *config = "CONFIG"; static int __init print_config(char *line, int *add) { --- diff/arch/um/kernel/exec_kern.c 2003-02-26 16:01:01.000000000 +0000 +++ source/arch/um/kernel/exec_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -32,10 +32,15 @@ CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp); } +extern void log_exec(char **argv, void *tty); + static int execve1(char *file, char **argv, char **env) { int error; +#ifdef CONFIG_TTY_LOG + log_exec(argv, current->tty); +#endif error = do_execve(file, argv, env, ¤t->thread.regs); if (error == 0){ current->ptrace &= ~PT_DTRACE; --- diff/arch/um/kernel/frame.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/frame.c 2004-02-09 10:39:51.000000000 +0000 @@ -279,7 +279,7 @@ struct sc_frame_raw raw_sc; struct si_frame_raw raw_si; void *stack, *sigstack; - unsigned long top, sig_top, base; + unsigned long top, base; stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); @@ -292,7 +292,6 @@ } top = (unsigned long) stack + PAGE_SIZE - sizeof(void *); - sig_top = (unsigned long) sigstack + PAGE_SIZE; /* Get the sigcontext, no sigrestorer layout */ raw_sc.restorer = 0; --- diff/arch/um/kernel/frame_kern.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/frame_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -6,7 +6,6 @@ #include "asm/ptrace.h" #include "asm/uaccess.h" #include "asm/signal.h" -#include "asm/uaccess.h" #include "asm/ucontext.h" #include "frame_kern.h" #include "sigcontext.h" @@ -29,12 +28,15 @@ sizeof(restorer))); } +extern int userspace_pid[]; + static int copy_sc_to_user(void *to, void *fp, struct pt_regs *from, struct arch_frame_data *arch) { return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), arch), - copy_sc_to_user_skas(to, fp, &from->regs, + copy_sc_to_user_skas(userspace_pid[0], to, fp, + &from->regs, current->thread.cr2, current->thread.err))); } --- diff/arch/um/kernel/helper.c 2003-01-02 10:43:04.000000000 +0000 +++ source/arch/um/kernel/helper.c 2004-02-09 10:39:51.000000000 +0000 @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -33,6 +32,7 @@ { struct helper_data *data = arg; char **argv = data->argv; + int errval; if(helper_pause){ signal(SIGHUP, helper_hup); @@ -41,8 +41,9 @@ if(data->pre_exec != NULL) (*data->pre_exec)(data->pre_data); execvp(argv[0], argv); + errval = errno; printk("execvp of '%s' failed - errno = %d\n", argv[0], errno); - write(data->fd, &errno, sizeof(errno)); + os_write_file(data->fd, &errval, sizeof(errval)); os_kill_process(os_getpid(), 0); return(0); } @@ -59,17 +60,20 @@ if((stack_out != NULL) && (*stack_out != 0)) stack = *stack_out; else stack = alloc_stack(0, um_in_interrupt()); - if(stack == 0) return(-ENOMEM); + if(stack == 0) + return(-ENOMEM); err = os_pipe(fds, 1, 0); - if(err){ - printk("run_helper : pipe failed, errno = %d\n", -err); - return(err); + if(err < 0){ + printk("run_helper : pipe failed, err = %d\n", -err); + goto out_free; } - if(fcntl(fds[1], F_SETFD, 1) != 0){ - printk("run_helper : setting FD_CLOEXEC failed, errno = %d\n", - errno); - return(-errno); + + err = os_set_exec_close(fds[1], 1); + if(err < 0){ + printk("run_helper : setting FD_CLOEXEC failed, err = %d\n", + -err); + goto out_close; } sp = stack + page_size() - sizeof(void *); @@ -80,23 +84,34 @@ pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data); if(pid < 0){ printk("run_helper : clone failed, errno = %d\n", errno); - return(-errno); + err = -errno; + goto out_close; } - close(fds[1]); - n = read(fds[0], &err, sizeof(err)); + + os_close_file(fds[1]); + n = os_read_file(fds[0], &err, sizeof(err)); if(n < 0){ - printk("run_helper : read on pipe failed, errno = %d\n", - errno); - return(-errno); + printk("run_helper : read on pipe failed, err = %d\n", -n); + err = n; + goto out_kill; } else if(n != 0){ waitpid(pid, NULL, 0); - pid = -err; + pid = -errno; } if(stack_out == NULL) free_stack(stack, 0); else *stack_out = stack; return(pid); + + out_kill: + os_kill_process(pid, 1); + out_close: + os_close_file(fds[0]); + os_close_file(fds[1]); + out_free: + free_stack(stack, 0); + return(err); } int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, @@ -117,9 +132,11 @@ } if(stack_out == NULL){ pid = waitpid(pid, &status, 0); - if(pid < 0) + if(pid < 0){ printk("run_helper_thread - wait failed, errno = %d\n", - pid); + errno); + pid = -errno; + } if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) printk("run_helper_thread - thread returned status " "0x%x\n", status); --- diff/arch/um/kernel/init_task.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/um/kernel/init_task.c 2004-02-09 10:39:51.000000000 +0000 @@ -8,7 +8,6 @@ #include "linux/module.h" #include "linux/sched.h" #include "linux/init_task.h" -#include "linux/version.h" #include "asm/uaccess.h" #include "asm/pgtable.h" #include "user_util.h" @@ -18,7 +17,7 @@ struct mm_struct init_mm = INIT_MM(init_mm); static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); - +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); EXPORT_SYMBOL(init_mm); /* @@ -43,26 +42,12 @@ __attribute__((__section__(".data.init_task"))) = { INIT_THREAD_INFO(init_task) }; -struct task_struct *alloc_task_struct(void) -{ - return((struct task_struct *) - __get_free_pages(GFP_KERNEL, CONFIG_KERNEL_STACK_ORDER)); -} - void unprotect_stack(unsigned long stack) { protect_memory(stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE, 1, 1, 0, 1); } -void free_task_struct(struct task_struct *task) -{ - /* free_pages decrements the page counter and only actually frees - * the pages if they are now not accessed by anything. - */ - free_pages((unsigned long) task, CONFIG_KERNEL_STACK_ORDER); -} - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically --- diff/arch/um/kernel/initrd_user.c 2002-10-16 04:27:19.000000000 +0100 +++ source/arch/um/kernel/initrd_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -6,7 +6,6 @@ #include #include #include -#include #include #include "user_util.h" @@ -19,13 +18,15 @@ { int fd, n; - if((fd = os_open_file(filename, of_read(OPENFLAGS()), 0)) < 0){ - printk("Opening '%s' failed - errno = %d\n", filename, errno); + fd = os_open_file(filename, of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Opening '%s' failed - err = %d\n", filename, -fd); return(-1); } - if((n = read(fd, buf, size)) != size){ - printk("Read of %d bytes from '%s' returned %d, errno = %d\n", - size, filename, n, errno); + n = os_read_file(fd, buf, size); + if(n != size){ + printk("Read of %d bytes from '%s' failed, err = %d\n", size, + filename, -n); return(-1); } return(0); --- diff/arch/um/kernel/irq.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/um/kernel/irq.c 2004-02-09 10:39:51.000000000 +0000 @@ -29,6 +29,7 @@ #include "user_util.h" #include "kern_util.h" #include "irq_user.h" +#include "irq_kern.h" static void register_irq_proc (unsigned int irq); @@ -83,65 +84,55 @@ end_none }; -/* Not changed */ -volatile unsigned long irq_err_count; - /* * Generic, controller-independent functions: */ -int get_irq_list(char *buf) +int show_interrupts(struct seq_file *p, void *v) { - int i, j; - unsigned long flags; + int i = *(loff_t *) v, j; struct irqaction * action; - char *p = buf; + unsigned long flags; - p += sprintf(p, " "); - for (j=0; jtypename); - p += sprintf(p, " %s", action->name); + seq_printf(p, " %14s", irq_desc[i].handler->typename); + seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) - p += sprintf(p, ", %s", action->name); - *p++ = '\n'; - end: + seq_printf(p, ", %s", action->name); + + seq_putc(p, '\n'); +skip: spin_unlock_irqrestore(&irq_desc[i].lock, flags); + } else if (i == NR_IRQS) { + seq_printf(p, "NMI: "); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "%10u ", nmi_count(j)); + seq_putc(p, '\n'); } - p += sprintf(p, "\n"); -#ifdef notdef -#ifdef CONFIG_SMP - p += sprintf(p, "LOC: "); - for (j = 0; j < num_online_cpus(); j++) - p += sprintf(p, "%10u ", - apic_timer_irqs[cpu_logical_map(j)]); - p += sprintf(p, "\n"); -#endif -#endif - p += sprintf(p, "ERR: %10lu\n", irq_err_count); - return p - buf; -} - -int show_interrupts(struct seq_file *p, void *v) -{ - return(0); + return 0; } /* @@ -230,8 +221,11 @@ void disable_irq(unsigned int irq) { + irq_desc_t *desc = irq_desc + irq; + disable_irq_nosync(irq); - synchronize_irq(irq); + if(desc->action) + synchronize_irq(irq); } /** @@ -252,7 +246,7 @@ spin_lock_irqsave(&desc->lock, flags); switch (desc->depth) { case 1: { - unsigned int status = desc->status & ~IRQ_DISABLED; + unsigned int status = desc->status & IRQ_DISABLED; desc->status = status; if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { desc->status = status | IRQ_REPLAY; @@ -282,13 +276,12 @@ * 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; irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); /* @@ -385,7 +378,7 @@ */ int request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) @@ -433,15 +426,19 @@ EXPORT_SYMBOL(request_irq); int um_request_irq(unsigned int irq, int fd, int type, - void (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) { - int retval; + int err; - retval = request_irq(irq, handler, irqflags, devname, dev_id); - if(retval) return(retval); - return(activate_fd(irq, fd, type, dev_id)); + err = request_irq(irq, handler, irqflags, devname, dev_id); + if(err) + return(err); + + if(fd != -1) + err = activate_fd(irq, fd, type, dev_id); + return(err); } /* this was setup_x86_irq but it seems pretty generic */ @@ -474,7 +471,8 @@ */ spin_lock_irqsave(&desc->lock,flags); p = &desc->action; - if ((old = *p) != NULL) { + old = *p; + if (old != NULL) { /* Can't share interrupts unless both agree to */ if (!(old->flags & new->flags & SA_SHIRQ)) { spin_unlock_irqrestore(&desc->lock,flags); @@ -586,12 +584,14 @@ unsigned long count, void *data) { int irq = (long) data, full_count = count, err; - cpumask_t new_value, tmp; + cpumask_t new_value; if (!irq_desc[irq].handler->set_affinity) return -EIO; err = cpumask_parse(buffer, count, new_value); + if(err) + return(err); #ifdef CONFIG_SMP /* @@ -614,6 +614,7 @@ int count, int *eof, void *data) { int len = cpumask_snprintf(page, count, *(cpumask_t *)data); + if (count - len < 2) return -EINVAL; len += sprintf(page + len, "\n"); --- diff/arch/um/kernel/irq_user.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/irq_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -49,7 +48,8 @@ if(smp_sigio_handler()) return; while(1){ - if((n = poll(pollfds, pollfds_num, 0)) < 0){ + n = poll(pollfds, pollfds_num, 0); + if(n < 0){ if(errno == EINTR) continue; printk("sigio_handler : poll returned %d, " "errno = %d\n", n, errno); @@ -366,34 +366,31 @@ void forward_ipi(int fd, int pid) { - if(fcntl(fd, F_SETOWN, pid) < 0){ - int save_errno = errno; - if(fcntl(fd, F_GETOWN, 0) != pid){ - printk("forward_ipi: F_SETOWN failed, fd = %d, " - "me = %d, target = %d, errno = %d\n", fd, - os_getpid(), pid, save_errno); - } - } + int err; + + err = os_set_owner(fd, pid); + if(err < 0) + printk("forward_ipi: set_owner failed, fd = %d, me = %d, " + "target = %d, err = %d\n", fd, os_getpid(), pid, -err); } void forward_interrupts(int pid) { struct irq_fd *irq; unsigned long flags; + int err; flags = irq_lock(); for(irq=active_fds;irq != NULL;irq = irq->next){ - if(fcntl(irq->fd, F_SETOWN, pid) < 0){ - int save_errno = errno; - if(fcntl(irq->fd, F_GETOWN, 0) != pid){ - /* XXX Just remove the irq rather than - * print out an infinite stream of these - */ - printk("Failed to forward %d to pid %d, " - "errno = %d\n", irq->fd, pid, - save_errno); - } + err = os_set_owner(irq->fd, pid); + if(err < 0){ + /* XXX Just remove the irq rather than + * print out an infinite stream of these + */ + printk("Failed to forward %d to pid %d, err = %d\n", + irq->fd, pid, -err); } + irq->pid = pid; } irq_unlock(flags); --- diff/arch/um/kernel/ksyms.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/ksyms.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -34,34 +34,62 @@ EXPORT_SYMBOL(flush_tlb_range); EXPORT_SYMBOL(host_task_size); EXPORT_SYMBOL(arch_validate); +EXPORT_SYMBOL(get_kmem_end); -EXPORT_SYMBOL(region_pa); -EXPORT_SYMBOL(region_va); -EXPORT_SYMBOL(phys_mem_map); -EXPORT_SYMBOL(page_mem_map); EXPORT_SYMBOL(page_to_phys); EXPORT_SYMBOL(phys_to_page); EXPORT_SYMBOL(high_physmem); EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(um_virt_to_phys); +EXPORT_SYMBOL(__virt_to_page); +EXPORT_SYMBOL(to_phys); +EXPORT_SYMBOL(to_virt); EXPORT_SYMBOL(mode_tt); EXPORT_SYMBOL(handle_page_fault); +#ifdef CONFIG_MODE_TT +EXPORT_SYMBOL(copy_from_user_tt); +EXPORT_SYMBOL(copy_to_user_tt); +#endif + +#ifdef CONFIG_MODE_SKAS +EXPORT_SYMBOL(copy_to_user_skas); +EXPORT_SYMBOL(copy_from_user_skas); +#endif + +EXPORT_SYMBOL(os_stat_fd); +EXPORT_SYMBOL(os_stat_file); +EXPORT_SYMBOL(os_access); +EXPORT_SYMBOL(os_print_error); +EXPORT_SYMBOL(os_get_exec_close); +EXPORT_SYMBOL(os_set_exec_close); EXPORT_SYMBOL(os_getpid); EXPORT_SYMBOL(os_open_file); EXPORT_SYMBOL(os_read_file); EXPORT_SYMBOL(os_write_file); EXPORT_SYMBOL(os_seek_file); +EXPORT_SYMBOL(os_lock_file); EXPORT_SYMBOL(os_pipe); EXPORT_SYMBOL(os_file_type); +EXPORT_SYMBOL(os_file_mode); +EXPORT_SYMBOL(os_file_size); +EXPORT_SYMBOL(os_flush_stdout); EXPORT_SYMBOL(os_close_file); +EXPORT_SYMBOL(os_set_fd_async); +EXPORT_SYMBOL(os_set_fd_block); EXPORT_SYMBOL(helper_wait); EXPORT_SYMBOL(os_shutdown_socket); +EXPORT_SYMBOL(os_create_unix_socket); EXPORT_SYMBOL(os_connect_socket); +EXPORT_SYMBOL(os_accept_connection); +EXPORT_SYMBOL(os_rcv_fd); EXPORT_SYMBOL(run_helper); EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(do_gettimeofday); +EXPORT_SYMBOL(do_settimeofday); + /* This is here because UML expands open to sys_open, not to a system * call instruction. */ @@ -90,3 +118,13 @@ EXPORT_SYMBOL(kmap_atomic_to_page); #endif +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- diff/arch/um/kernel/mem.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/um/kernel/mem.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,74 +1,67 @@ /* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ -#include "linux/config.h" -#include "linux/module.h" -#include "linux/types.h" +#include "linux/stddef.h" +#include "linux/kernel.h" #include "linux/mm.h" -#include "linux/fs.h" -#include "linux/init.h" #include "linux/bootmem.h" #include "linux/swap.h" -#include "linux/slab.h" -#include "linux/vmalloc.h" #include "linux/highmem.h" +#include "linux/gfp.h" #include "asm/page.h" -#include "asm/pgtable.h" +#include "asm/fixmap.h" #include "asm/pgalloc.h" -#include "asm/bitops.h" -#include "asm/uaccess.h" -#include "asm/tlb.h" #include "user_util.h" #include "kern_util.h" -#include "mem_user.h" -#include "mem.h" #include "kern.h" -#include "init.h" -#include "os.h" -#include "mode_kern.h" +#include "mem_user.h" #include "uml_uaccess.h" +#include "os.h" + +extern char __binary_start; /* Changed during early boot */ -pgd_t swapper_pg_dir[1024]; -unsigned long high_physmem; -unsigned long vm_start; -unsigned long vm_end; -unsigned long highmem; unsigned long *empty_zero_page = NULL; unsigned long *empty_bad_page = NULL; - -/* Not modified */ -const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; - -extern char __init_begin, __init_end; -extern long physmem_size; - -/* Not changed by UML */ -DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); - -/* Changed during early boot */ +pgd_t swapper_pg_dir[1024]; +unsigned long highmem; int kmalloc_ok = 0; -#define NREGIONS (phys_region_index(0xffffffff) - phys_region_index(0x0) + 1) -struct mem_region *regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = NULL }; -#define REGION_SIZE ((0xffffffff & ~REGION_MASK) + 1) - -/* Changed during early boot */ static unsigned long brk_end; +static unsigned long totalram_pages = 0; + +void unmap_physmem(void) +{ + os_unmap_memory((void *) brk_end, uml_reserved - brk_end); +} static void map_cb(void *unused) { map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); } -void unmap_physmem(void) +#ifdef CONFIG_HIGHMEM +static void setup_highmem(unsigned long highmem_start, + unsigned long highmem_len) { - os_unmap_memory((void *) brk_end, uml_reserved - brk_end); -} + struct page *page; + unsigned long highmem_pfn; + int i; -extern char __binary_start; + highmem_start_page = virt_to_page(highmem_start); + + highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT; + for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){ + page = &mem_map[highmem_pfn + i]; + ClearPageReserved(page); + set_bit(PG_highmem, &page->flags); + atomic_set(&page->count, 1); + __free_page(page); + } +} +#endif void mem_init(void) { @@ -103,50 +96,15 @@ totalhigh_pages = highmem >> PAGE_SHIFT; totalram_pages += totalhigh_pages; num_physpages = totalram_pages; - max_mapnr = totalram_pages; max_pfn = totalram_pages; printk(KERN_INFO "Memory: %luk available\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10)); kmalloc_ok = 1; -} - -/* Changed during early boot */ -static unsigned long kmem_top = 0; - -unsigned long get_kmem_end(void) -{ - if(kmem_top == 0) - kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas); - return(kmem_top); -} - -void set_kmem_end(unsigned long new) -{ - kmem_top = new; -} #ifdef CONFIG_HIGHMEM -/* Changed during early boot */ -pte_t *kmap_pte; -pgprot_t kmap_prot; - -EXPORT_SYMBOL(kmap_prot); -EXPORT_SYMBOL(kmap_pte); - -#define kmap_get_fixmap_pte(vaddr) \ - pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) - -void __init kmap_init(void) -{ - unsigned long kmap_vstart; - - /* cache the first kmap pte */ - kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); - kmap_pte = kmap_get_fixmap_pte(kmap_vstart); - - kmap_prot = PAGE_KERNEL; + setup_highmem(end_iomem, highmem); +#endif } -#endif /* CONFIG_HIGHMEM */ static void __init fixrange_init(unsigned long start, unsigned long end, pgd_t *pgd_base) @@ -178,76 +136,24 @@ } } -int init_maps(struct mem_region *region) -{ - struct page *p, *map; - int i, n, len; - - if(region == &physmem_region){ - region->mem_map = mem_map; - return(0); - } - else if(region->mem_map != NULL) return(0); - - n = region->len >> PAGE_SHIFT; - len = n * sizeof(struct page); - if(kmalloc_ok){ - map = kmalloc(len, GFP_KERNEL); - if(map == NULL) map = vmalloc(len); - } - else map = alloc_bootmem_low_pages(len); - - if(map == NULL) - return(-ENOMEM); - for(i = 0; i < n; i++){ - p = &map[i]; - set_page_count(p, 0); - SetPageReserved(p); - INIT_LIST_HEAD(&p->list); - } - region->mem_map = map; - return(0); -} +#if CONFIG_HIGHMEM +pte_t *kmap_pte; +pgprot_t kmap_prot; -DECLARE_MUTEX(regions_sem); +#define kmap_get_fixmap_pte(vaddr) \ + pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) -static int setup_one_range(int fd, char *driver, unsigned long start, - unsigned long pfn, int len, - struct mem_region *region) +void __init kmap_init(void) { - int i; - - down(®ions_sem); - for(i = 0; i < NREGIONS; i++){ - if(regions[i] == NULL) break; - } - if(i == NREGIONS){ - printk("setup_range : no free regions\n"); - i = -1; - goto out; - } - - if(fd == -1) - fd = create_mem_file(len); + unsigned long kmap_vstart; - if(region == NULL){ - region = alloc_bootmem_low_pages(sizeof(*region)); - if(region == NULL) - panic("Failed to allocating mem_region"); - } + /* cache the first kmap pte */ + kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); + kmap_pte = kmap_get_fixmap_pte(kmap_vstart); - *region = ((struct mem_region) { .driver = driver, - .start_pfn = pfn, - .start = start, - .len = len, - .fd = fd } ); - regions[i] = region; - out: - up(®ions_sem); - return(i); + kmap_prot = PAGE_KERNEL; } -#ifdef CONFIG_HIGHMEM static void init_highmem(void) { pgd_t *pgd; @@ -268,63 +174,20 @@ kmap_init(); } - -void setup_highmem(unsigned long len) -{ - struct mem_region *region; - struct page *page, *map; - unsigned long phys; - int i, cur, index; - - phys = physmem_size; - do { - cur = min(len, (unsigned long) REGION_SIZE); - i = setup_one_range(-1, NULL, -1, phys >> PAGE_SHIFT, cur, - NULL); - if(i == -1){ - printk("setup_highmem - setup_one_range failed\n"); - return; - } - region = regions[i]; - index = phys / PAGE_SIZE; - region->mem_map = &mem_map[index]; - - map = region->mem_map; - for(i = 0; i < (cur >> PAGE_SHIFT); i++){ - page = &map[i]; - ClearPageReserved(page); - set_bit(PG_highmem, &page->flags); - atomic_set(&page->count, 1); - __free_page(page); - } - phys += cur; - len -= cur; - } while(len > 0); -} -#endif +#endif /* CONFIG_HIGHMEM */ void paging_init(void) { - struct mem_region *region; - unsigned long zones_size[MAX_NR_ZONES], start, end, vaddr; - int i, index; + unsigned long zones_size[MAX_NR_ZONES], vaddr; + int i; empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); for(i=0;i> PAGE_SHIFT) - - (uml_physmem >> PAGE_SHIFT); + zones_size[0] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT); zones_size[2] = highmem >> PAGE_SHIFT; free_area_init(zones_size); - start = phys_region_index(__pa(uml_physmem)); - end = phys_region_index(__pa(high_physmem - 1)); - for(i = start; i <= end; i++){ - region = regions[i]; - index = (region->start - uml_physmem) / PAGE_SIZE; - region->mem_map = &mem_map[index]; - if(i > start) free_bootmem(__pa(region->start), region->len); - } /* * Fixed mappings, only the page table structure has to be @@ -335,15 +198,33 @@ #ifdef CONFIG_HIGHMEM init_highmem(); - setup_highmem(highmem); #endif } -pte_t __bad_page(void) +struct page *arch_validate(struct page *page, int mask, int order) { - clear_page(empty_bad_page); - return pte_mkdirty(mk_pte((struct page *) empty_bad_page, - PAGE_SHARED)); + unsigned long addr, zero = 0; + int i; + + again: + if(page == NULL) return(page); + if(PageHighMem(page)) return(page); + + addr = (unsigned long) page_address(page); + for(i = 0; i < (1 << order); i++){ + current->thread.fault_addr = (void *) addr; + if(__do_copy_to_user((void *) addr, &zero, + sizeof(zero), + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)){ + if(!(mask & __GFP_WAIT)) return(NULL); + else break; + } + addr += PAGE_SIZE; + } + if(i == (1 << order)) return(page); + page = alloc_pages(mask, order); + goto again; } /* This can't do anything because nothing in the kernel image can be freed @@ -401,395 +282,6 @@ printk("%d pages swap cached\n", cached); } -static int __init uml_mem_setup(char *line, int *add) -{ - char *retptr; - physmem_size = memparse(line,&retptr); - return 0; -} -__uml_setup("mem=", uml_mem_setup, -"mem=\n" -" This controls how much \"physical\" memory the kernel allocates\n" -" for the system. The size is specified as a number followed by\n" -" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n" -" This is not related to the amount of memory in the physical\n" -" machine. It can be more, and the excess, if it's ever used, will\n" -" just be swapped out.\n Example: mem=64M\n\n" -); - -struct page *arch_validate(struct page *page, int mask, int order) -{ - unsigned long addr, zero = 0; - int i; - - again: - if(page == NULL) return(page); - if(PageHighMem(page)) return(page); - - addr = (unsigned long) page_address(page); - for(i = 0; i < (1 << order); i++){ - current->thread.fault_addr = (void *) addr; - if(__do_copy_to_user((void *) addr, &zero, - sizeof(zero), - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)){ - if(!(mask & __GFP_WAIT)) return(NULL); - else break; - } - addr += PAGE_SIZE; - } - if(i == (1 << order)) return(page); - page = alloc_pages(mask, order); - goto again; -} - -DECLARE_MUTEX(vm_reserved_sem); -static struct list_head vm_reserved = LIST_HEAD_INIT(vm_reserved); - -/* Static structures, linked in to the list in early boot */ -static struct vm_reserved head = { - .list = LIST_HEAD_INIT(head.list), - .start = 0, - .end = 0xffffffff -}; - -static struct vm_reserved tail = { - .list = LIST_HEAD_INIT(tail.list), - .start = 0, - .end = 0xffffffff -}; - -void set_usable_vm(unsigned long start, unsigned long end) -{ - list_add(&head.list, &vm_reserved); - list_add(&tail.list, &head.list); - head.end = start; - tail.start = end; -} - -int reserve_vm(unsigned long start, unsigned long end, void *e) - -{ - struct vm_reserved *entry = e, *reserved, *prev; - struct list_head *ele; - int err; - - down(&vm_reserved_sem); - list_for_each(ele, &vm_reserved){ - reserved = list_entry(ele, struct vm_reserved, list); - if(reserved->start >= end) goto found; - } - panic("Reserved vm out of range"); - found: - prev = list_entry(ele->prev, struct vm_reserved, list); - if(prev->end > start) - panic("Can't reserve vm"); - if(entry == NULL) - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if(entry == NULL){ - printk("reserve_vm : Failed to allocate entry\n"); - err = -ENOMEM; - goto out; - } - *entry = ((struct vm_reserved) - { .list = LIST_HEAD_INIT(entry->list), - .start = start, - .end = end }); - list_add(&entry->list, &prev->list); - err = 0; - out: - up(&vm_reserved_sem); - return(0); -} - -unsigned long get_vm(unsigned long len) -{ - struct vm_reserved *this, *next; - struct list_head *ele; - unsigned long start; - int err; - - down(&vm_reserved_sem); - list_for_each(ele, &vm_reserved){ - this = list_entry(ele, struct vm_reserved, list); - next = list_entry(ele->next, struct vm_reserved, list); - if((this->start < next->start) && - (this->end + len + PAGE_SIZE <= next->start)) - goto found; - } - up(&vm_reserved_sem); - return(0); - found: - up(&vm_reserved_sem); - start = (unsigned long) UML_ROUND_UP(this->end) + PAGE_SIZE; - err = reserve_vm(start, start + len, NULL); - if(err) return(0); - return(start); -} - -int nregions(void) -{ - return(NREGIONS); -} - -void setup_range(int fd, char *driver, unsigned long start, unsigned long pfn, - unsigned long len, int need_vm, struct mem_region *region, - void *reserved) -{ - int i, cur; - - do { - cur = min(len, (unsigned long) REGION_SIZE); - i = setup_one_range(fd, driver, start, pfn, cur, region); - region = regions[i]; - if(need_vm && setup_region(region, reserved)){ - kfree(region); - regions[i] = NULL; - return; - } - start += cur; - if(pfn != -1) pfn += cur; - len -= cur; - } while(len > 0); -} - -struct iomem { - char *name; - int fd; - unsigned long size; -}; - -/* iomem regions can only be added on the command line at the moment. - * Locking will be needed when they can be added via mconsole. - */ - -struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = - { .name = NULL, - .fd = -1, - .size = 0 } }; - -int num_iomem_regions = 0; - -void add_iomem(char *name, int fd, unsigned long size) -{ - if(num_iomem_regions == sizeof(iomem_regions)/sizeof(iomem_regions[0])) - return; - size = (size + PAGE_SIZE - 1) & PAGE_MASK; - iomem_regions[num_iomem_regions++] = - ((struct iomem) { .name = name, - .fd = fd, - .size = size } ); -} - -int setup_iomem(void) -{ - struct iomem *iomem; - int i; - - for(i = 0; i < num_iomem_regions; i++){ - iomem = &iomem_regions[i]; - setup_range(iomem->fd, iomem->name, -1, -1, iomem->size, 1, - NULL, NULL); - } - return(0); -} - -__initcall(setup_iomem); - -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) -#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) - -/* Changed during early boot */ -static struct mem_region physmem_region; -static struct vm_reserved physmem_reserved; - -void setup_physmem(unsigned long start, unsigned long reserve_end, - unsigned long len) -{ - struct mem_region *region = &physmem_region; - struct vm_reserved *reserved = &physmem_reserved; - unsigned long cur, pfn = 0; - int do_free = 1, bootmap_size; - - do { - cur = min(len, (unsigned long) REGION_SIZE); - if(region == NULL) - region = alloc_bootmem_low_pages(sizeof(*region)); - if(reserved == NULL) - reserved = alloc_bootmem_low_pages(sizeof(*reserved)); - if((region == NULL) || (reserved == NULL)) - panic("Couldn't allocate physmem region or vm " - "reservation\n"); - setup_range(-1, NULL, start, pfn, cur, 1, region, reserved); - - if(do_free){ - unsigned long reserve = reserve_end - start; - int pfn = PFN_UP(__pa(reserve_end)); - int delta = (len - reserve) >> PAGE_SHIFT; - - bootmap_size = init_bootmem(pfn, pfn + delta); - free_bootmem(__pa(reserve_end) + bootmap_size, - cur - bootmap_size - reserve); - do_free = 0; - } - start += cur; - pfn += cur >> PAGE_SHIFT; - len -= cur; - region = NULL; - reserved = NULL; - } while(len > 0); -} - -struct mem_region *phys_region(unsigned long phys) -{ - unsigned int n = phys_region_index(phys); - - if(regions[n] == NULL) - panic("Physical address in uninitialized region"); - return(regions[n]); -} - -unsigned long phys_offset(unsigned long phys) -{ - return(phys_addr(phys)); -} - -struct page *phys_mem_map(unsigned long phys) -{ - return((struct page *) phys_region(phys)->mem_map); -} - -struct page *pte_mem_map(pte_t pte) -{ - return(phys_mem_map(pte_val(pte))); -} - -struct mem_region *page_region(struct page *page, int *index_out) -{ - int i; - struct mem_region *region; - struct page *map; - - for(i = 0; i < NREGIONS; i++){ - region = regions[i]; - if(region == NULL) continue; - map = region->mem_map; - if((page >= map) && (page < &map[region->len >> PAGE_SHIFT])){ - if(index_out != NULL) *index_out = i; - return(region); - } - } - panic("No region found for page"); - return(NULL); -} - -unsigned long page_to_pfn(struct page *page) -{ - struct mem_region *region = page_region(page, NULL); - - return(region->start_pfn + (page - (struct page *) region->mem_map)); -} - -struct mem_region *pfn_to_region(unsigned long pfn, int *index_out) -{ - struct mem_region *region; - int i; - - for(i = 0; i < NREGIONS; i++){ - region = regions[i]; - if(region == NULL) - continue; - - if((region->start_pfn <= pfn) && - (region->start_pfn + (region->len >> PAGE_SHIFT) > pfn)){ - if(index_out != NULL) - *index_out = i; - return(region); - } - } - return(NULL); -} - -struct page *pfn_to_page(unsigned long pfn) -{ - struct mem_region *region = pfn_to_region(pfn, NULL); - struct page *mem_map = (struct page *) region->mem_map; - - return(&mem_map[pfn - region->start_pfn]); -} - -unsigned long phys_to_pfn(unsigned long p) -{ - struct mem_region *region = regions[phys_region_index(p)]; - - return(region->start_pfn + (phys_addr(p) >> PAGE_SHIFT)); -} - -unsigned long pfn_to_phys(unsigned long pfn) -{ - int n; - struct mem_region *region = pfn_to_region(pfn, &n); - - return(mk_phys((pfn - region->start_pfn) << PAGE_SHIFT, n)); -} - -struct page *page_mem_map(struct page *page) -{ - return((struct page *) page_region(page, NULL)->mem_map); -} - -extern unsigned long region_pa(void *virt) -{ - struct mem_region *region; - unsigned long addr = (unsigned long) virt; - int i; - - for(i = 0; i < NREGIONS; i++){ - region = regions[i]; - if(region == NULL) continue; - if((region->start <= addr) && - (addr <= region->start + region->len)) - return(mk_phys(addr - region->start, i)); - } - panic("region_pa : no region for virtual address"); - return(0); -} - -extern void *region_va(unsigned long phys) -{ - return((void *) (phys_region(phys)->start + phys_addr(phys))); -} - -unsigned long page_to_phys(struct page *page) -{ - int n; - struct mem_region *region = page_region(page, &n); - struct page *map = region->mem_map; - return(mk_phys((page - map) << PAGE_SHIFT, n)); -} - -struct page *phys_to_page(unsigned long phys) -{ - struct page *mem_map; - - mem_map = phys_mem_map(phys); - return(mem_map + (phys_offset(phys) >> PAGE_SHIFT)); -} - -static int setup_mem_maps(void) -{ - struct mem_region *region; - int i; - - for(i = 0; i < NREGIONS; i++){ - region = regions[i]; - if((region != NULL) && (region->fd > 0)) init_maps(region); - } - return(0); -} - -__initcall(setup_mem_maps); - /* * Allocate and free page tables. */ --- diff/arch/um/kernel/mem_user.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/mem_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -34,10 +34,9 @@ #include #include #include -#include #include #include -#include +#include #include #include #include "kern_util.h" @@ -47,105 +46,145 @@ #include "init.h" #include "os.h" #include "tempfile.h" +#include "kern_constants.h" extern struct mem_region physmem_region; #define TEMPNAME_TEMPLATE "vm_file-XXXXXX" -int create_mem_file(unsigned long len) +static int create_tmp_file(unsigned long len) { - int fd; + int fd, err; char zero; fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1); - if (fchmod(fd, 0777) < 0){ - perror("fchmod"); + if(fd < 0) { + os_print_error(fd, "make_tempfile"); + exit(1); + } + + err = os_mode_fd(fd, 0777); + if(err < 0){ + os_print_error(err, "os_mode_fd"); exit(1); } - if(os_seek_file(fd, len) < 0){ - perror("lseek"); + err = os_seek_file(fd, len); + if(err < 0){ + os_print_error(err, "os_seek_file"); exit(1); } zero = 0; - if(write(fd, &zero, 1) != 1){ - perror("write"); + err = os_write_file(fd, &zero, 1); + if(err != 1){ + os_print_error(err, "os_write_file"); exit(1); } - if(fcntl(fd, F_SETFD, 1) != 0) - perror("Setting FD_CLOEXEC failed"); + return(fd); } -int setup_region(struct mem_region *region, void *entry) +static int have_devanon = 0; + +void check_devanon(void) +{ + int fd; + + printk("Checking for /dev/anon on the host..."); + fd = open("/dev/anon", O_RDWR); + if(fd < 0){ + printk("Not available (open failed with errno %d)\n", errno); + return; + } + + printk("OK\n"); + have_devanon = 1; +} + +static int create_anon_file(unsigned long len) { - void *loc, *start; - char *driver; - int err, offset; - - if(region->start != -1){ - err = reserve_vm(region->start, - region->start + region->len, entry); - if(err){ - printk("setup_region : failed to reserve " - "0x%x - 0x%x for driver '%s'\n", - region->start, - region->start + region->len, - region->driver); - return(-1); - } - } - else region->start = get_vm(region->len); - if(region->start == 0){ - if(region->driver == NULL) driver = "physmem"; - else driver = region->driver; - printk("setup_region : failed to find vm for " - "driver '%s' (length %d)\n", driver, region->len); - return(-1); - } - if(region->start == uml_physmem){ - start = (void *) uml_reserved; - offset = uml_reserved - uml_physmem; - } - else { - start = (void *) region->start; - offset = 0; - } - - loc = mmap(start, region->len - offset, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_FIXED, region->fd, offset); - if(loc != start){ - perror("Mapping memory"); + void *addr; + int fd; + + fd = open("/dev/anon", O_RDWR); + if(fd < 0) { + os_print_error(fd, "opening /dev/anon"); exit(1); } - return(0); + + addr = mmap(NULL, len, PROT_READ | PROT_WRITE , MAP_PRIVATE, fd, 0); + if(addr == MAP_FAILED){ + os_print_error((int) addr, "mapping physmem file"); + exit(1); + } + munmap(addr, len); + + return(fd); +} + +int create_mem_file(unsigned long len) +{ + int err, fd; + + if(have_devanon) + fd = create_anon_file(len); + else fd = create_tmp_file(len); + + err = os_set_exec_close(fd, 1); + if(err < 0) + os_print_error(err, "exec_close"); + return(fd); } +struct iomem_region *iomem_regions = NULL; +int iomem_size = 0; + static int __init parse_iomem(char *str, int *add) { - struct stat buf; + struct iomem_region *new; + struct uml_stat buf; char *file, *driver; - int fd; + int fd, err; driver = str; file = strchr(str,','); if(file == NULL){ - printk("parse_iomem : failed to parse iomem\n"); - return(1); + printf("parse_iomem : failed to parse iomem\n"); + goto out; } *file = '\0'; file++; fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0); if(fd < 0){ - printk("parse_iomem - Couldn't open io file, errno = %d\n", - errno); - return(1); - } - if(fstat(fd, &buf) < 0) { - printk("parse_iomem - cannot fstat file, errno = %d\n", errno); - return(1); + os_print_error(fd, "parse_iomem - Couldn't open io file"); + goto out; } - add_iomem(driver, fd, buf.st_size); + + err = os_stat_fd(fd, &buf); + if(err < 0){ + os_print_error(err, "parse_iomem - cannot stat_fd file"); + goto out_close; + } + + new = malloc(sizeof(*new)); + if(new == NULL){ + perror("Couldn't allocate iomem_region struct"); + goto out_close; + } + + *new = ((struct iomem_region) { .next = iomem_regions, + .driver = driver, + .fd = fd, + .size = buf.ust_size, + .phys = 0, + .virt = 0 }); + iomem_regions = new; + iomem_size += new->size + UM_KERN_PAGE_SIZE; + return(0); + out_close: + os_close_file(fd); + out: + return(1); } __uml_setup("iomem=", parse_iomem, @@ -153,73 +192,20 @@ " Configure as an IO memory region named .\n\n" ); -#ifdef notdef -int logging = 0; -int logging_fd = -1; - -int logging_line = 0; -char logging_buf[256]; - -void log(char *fmt, ...) -{ - va_list ap; - struct timeval tv; - struct openflags flags; - - if(logging == 0) return; - if(logging_fd < 0){ - flags = of_create(of_trunc(of_rdrw(OPENFLAGS()))); - logging_fd = os_open_file("log", flags, 0644); - } - gettimeofday(&tv, NULL); - sprintf(logging_buf, "%d\t %u.%u ", logging_line++, tv.tv_sec, - tv.tv_usec); - va_start(ap, fmt); - vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap); - va_end(ap); - write(logging_fd, logging_buf, strlen(logging_buf)); -} -#endif - -int map_memory(unsigned long virt, unsigned long phys, unsigned long len, - int r, int w, int x) -{ - struct mem_region *region = phys_region(phys); - - return(os_map_memory((void *) virt, region->fd, phys_offset(phys), len, - r, w, x)); -} - int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, int must_succeed) { - if(os_protect_memory((void *) addr, len, r, w, x) < 0){ + int err; + + err = os_protect_memory((void *) addr, len, r, w, x); + if(err < 0){ if(must_succeed) - panic("protect failed, errno = %d", errno); - else return(-errno); + panic("protect failed, err = %d", -err); + else return(err); } return(0); } -unsigned long find_iomem(char *driver, unsigned long *len_out) -{ - struct mem_region *region; - int i, n; - - n = nregions(); - for(i = 0; i < n; i++){ - region = regions[i]; - if(region == NULL) continue; - if((region->driver != NULL) && - !strcmp(region->driver, driver)){ - *len_out = region->len; - return(region->start); - } - } - *len_out = 0; - return 0; -} - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically --- diff/arch/um/kernel/process.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/process.c 2004-02-09 10:39:51.000000000 +0000 @@ -9,12 +9,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -58,7 +56,11 @@ { int flags = altstack ? SA_ONSTACK : 0; - set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags, + /* NODEFER is set here because SEGV isn't turned back on when the + * handler is ready to receive signals. This causes any segfault + * during a copy_user to kill the process because the fault is blocked. + */ + set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags | SA_NODEFER, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); @@ -72,7 +74,6 @@ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGUSR2, (__sighandler_t) sig_handler, SA_NOMASK | flags, -1); - (void) CHOOSE_MODE(signal(SIGCHLD, SIG_IGN), (void *) 0); signal(SIGHUP, SIG_IGN); init_irq_signals(altstack); @@ -123,11 +124,12 @@ /* Start the process and wait for it to kill itself */ new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg); if(new_pid < 0) return(-errno); - while((err = waitpid(new_pid, &status, 0) < 0) && (errno == EINTR)) ; + while(((err = waitpid(new_pid, &status, 0)) < 0) && (errno == EINTR)) ; if(err < 0) panic("Waiting for outer trampoline failed - errno = %d", errno); if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL)) - panic("outer trampoline didn't exit with SIGKILL"); + panic("outer trampoline didn't exit with SIGKILL, " + "status = %d", status); return(arg.pid); } @@ -138,7 +140,7 @@ os_stop_process(os_getpid()); - if(read(fd, &c, sizeof(c)) != sizeof(c)) + if(os_read_file(fd, &c, sizeof(c)) != sizeof(c)) panic("read failed in suspend_new_thread"); } @@ -233,7 +235,7 @@ int n; *jmp_ptr = &buf; - n = setjmp(buf); + n = sigsetjmp(buf, 1); if(n != 0) return(n); (*fn)(arg); @@ -273,7 +275,7 @@ stop_ptraced_child(pid, stack, 1); printf("Checking for /proc/mm..."); - if(access("/proc/mm", W_OK)){ + if(os_access("/proc/mm", OS_ACC_W_OK) < 0){ printf("not found\n"); ret = 0; } --- diff/arch/um/kernel/process_kern.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/um/kernel/process_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -16,6 +16,7 @@ #include "linux/module.h" #include "linux/init.h" #include "linux/capability.h" +#include "linux/spinlock.h" #include "asm/unistd.h" #include "asm/mman.h" #include "asm/segment.h" @@ -23,7 +24,6 @@ #include "asm/pgtable.h" #include "asm/processor.h" #include "asm/tlbflush.h" -#include "asm/spinlock.h" #include "asm/uaccess.h" #include "asm/user.h" #include "user_util.h" @@ -52,17 +52,12 @@ struct task_struct *get_task(int pid, int require) { - struct task_struct *task, *ret; + struct task_struct *ret; - ret = NULL; read_lock(&tasklist_lock); - for_each_process(task){ - if(task->pid == pid){ - ret = task; - break; - } - } + ret = find_task_by_pid(pid); read_unlock(&tasklist_lock); + if(require && (ret == NULL)) panic("get_task couldn't find a task\n"); return(ret); } @@ -95,7 +90,8 @@ int flags = GFP_KERNEL; if(atomic) flags |= GFP_ATOMIC; - if((page = __get_free_pages(flags, order)) == 0) + page = __get_free_pages(flags, order); + if(page == 0) return(0); stack_protections(page); return(page); @@ -103,13 +99,15 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { - struct task_struct *p; + int pid; current->thread.request.u.thread.proc = fn; current->thread.request.u.thread.arg = arg; - p = do_fork(CLONE_VM | flags, 0, NULL, 0, NULL, NULL); - if(IS_ERR(p)) panic("do_fork failed in kernel_thread"); - return(p->pid); + pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, NULL, 0, NULL, + NULL); + if(pid < 0) + panic("do_fork failed in kernel_thread, errno = %d", pid); + return(pid); } void switch_mm(struct mm_struct *prev, struct mm_struct *next, @@ -129,7 +127,7 @@ { external_pid(task), task }); } -void *switch_to(void *prev, void *next, void *last) +void *_switch_to(void *prev, void *next, void *last) { return(CHOOSE_MODE(switch_to_tt(prev, next), switch_to_skas(prev, next))); @@ -149,7 +147,7 @@ void exit_thread(void) { CHOOSE_MODE(exit_thread_tt(), exit_thread_skas()); - unprotect_stack((unsigned long) current->thread_info); + unprotect_stack((unsigned long) current_thread); } void *get_current(void) @@ -157,6 +155,10 @@ return(current); } +void prepare_to_copy(struct task_struct *tsk) +{ +} + int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, unsigned long stack_top, struct task_struct * p, struct pt_regs *regs) @@ -190,7 +192,7 @@ void default_idle(void) { - idle_timer(); + uml_idle_timer(); atomic_inc(&init_mm.mm_count); current->mm = &init_mm; @@ -367,10 +369,15 @@ return(clear_user(buf, size)); } +int strlen_user_proc(char *str) +{ + return(strlen_user(str)); +} + int smp_sigio_handler(void) { #ifdef CONFIG_SMP - int cpu = current->thread_info->cpu; + int cpu = current_thread->cpu; IPI_handler(cpu); if(cpu != 0) return(1); @@ -385,7 +392,7 @@ int cpu(void) { - return(current->thread_info->cpu); + return(current_thread->cpu); } /* --- diff/arch/um/kernel/ptrace.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/ptrace.c 2004-02-09 10:39:51.000000000 +0000 @@ -311,11 +311,8 @@ /* 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(); + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); /* * this isn't the same as continuing with a signal, but it will do --- diff/arch/um/kernel/reboot.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/um/kernel/reboot.c 2004-02-09 10:39:51.000000000 +0000 @@ -15,6 +15,7 @@ #ifdef CONFIG_SMP static void kill_idlers(int me) { +#ifdef CONFIG_MODE_TT struct task_struct *p; int i; @@ -23,6 +24,7 @@ if((p != NULL) && (p->thread.mode.tt.extern_pid != me)) os_kill_process(p->thread.mode.tt.extern_pid, 0); } +#endif } #endif --- diff/arch/um/kernel/sigio_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/sigio_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -6,18 +6,21 @@ #include "linux/kernel.h" #include "linux/list.h" #include "linux/slab.h" -#include "asm/irq.h" +#include "linux/signal.h" +#include "linux/interrupt.h" #include "init.h" #include "sigio.h" #include "irq_user.h" +#include "irq_kern.h" /* Protected by sigio_lock() called from write_sigio_workaround */ static int sigio_irq_fd = -1; -void sigio_interrupt(int irq, void *data, struct pt_regs *unused) +irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused) { read_sigio_fd(sigio_irq_fd); reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ); + return(IRQ_HANDLED); } int write_sigio_irq(int fd) --- diff/arch/um/kernel/sigio_user.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/sigio_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -26,7 +25,7 @@ int pty_close_sigio = 0; /* Used as a flag during SIGIO testing early in boot */ -static int got_sigio = 0; +static volatile int got_sigio = 0; void __init handler(int sig) { @@ -45,7 +44,7 @@ info->err = 0; if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) - info->err = errno; + info->err = -errno; } void __init check_one_sigio(void (*proc)(int, int)) @@ -53,11 +52,11 @@ struct sigaction old, new; struct termios tt; struct openpty_arg pty = { .master = -1, .slave = -1 }; - int master, slave, flags; + int master, slave, err; initial_thread_cb(openpty_cb, &pty); if(pty.err){ - printk("openpty failed, errno = %d\n", pty.err); + printk("openpty failed, errno = %d\n", -pty.err); return; } @@ -69,23 +68,16 @@ return; } + /* XXX These can fail with EINTR */ if(tcgetattr(master, &tt) < 0) panic("check_sigio : tcgetattr failed, errno = %d\n", errno); cfmakeraw(&tt); if(tcsetattr(master, TCSADRAIN, &tt) < 0) panic("check_sigio : tcsetattr failed, errno = %d\n", errno); - if((flags = fcntl(master, F_GETFL)) < 0) - panic("tty_fds : fcntl F_GETFL failed, errno = %d\n", errno); - - if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || - (fcntl(master, F_SETOWN, os_getpid()) < 0)) - panic("check_sigio : fcntl F_SETFL or F_SETOWN failed, " - "errno = %d\n", errno); - - if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) - panic("check_sigio : fcntl F_SETFL failed, errno = %d\n", - errno); + err = os_sigio_async(master, slave); + if(err < 0) + panic("tty_fds : sigio_async failed, err = %d\n", -err); if(sigaction(SIGIO, NULL, &old) < 0) panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); @@ -97,8 +89,8 @@ got_sigio = 0; (*proc)(master, slave); - close(master); - close(slave); + os_close_file(master); + os_close_file(slave); if(sigaction(SIGIO, &old, NULL) < 0) panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); @@ -112,25 +104,25 @@ printk("Checking that host ptys support output SIGIO..."); memset(buf, 0, sizeof(buf)); - while(write(master, buf, sizeof(buf)) > 0) ; + + while(os_write_file(master, buf, sizeof(buf)) > 0) ; if(errno != EAGAIN) panic("check_sigio : write failed, errno = %d\n", errno); - - while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; + while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; if(got_sigio){ printk("Yes\n"); pty_output_sigio = 1; } - else if(errno == EAGAIN) printk("No, enabling workaround\n"); - else panic("check_sigio : read failed, errno = %d\n", errno); + else if(n == -EAGAIN) printk("No, enabling workaround\n"); + else panic("check_sigio : read failed, err = %d\n", n); } static void tty_close(int master, int slave) { printk("Checking that host ptys support SIGIO on close..."); - close(slave); + os_close_file(slave); if(got_sigio){ printk("Yes\n"); pty_close_sigio = 1; @@ -140,7 +132,8 @@ void __init check_sigio(void) { - if(access("/dev/ptmx", R_OK) && access("/dev/ptyp0", R_OK)){ + if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && + (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ printk("No pseudo-terminals available - skipping pty SIGIO " "check\n"); return; @@ -201,11 +194,10 @@ p = &fds->poll[i]; if(p->revents == 0) continue; if(p->fd == sigio_private[1]){ - n = read(sigio_private[1], &c, sizeof(c)); + n = os_read_file(sigio_private[1], &c, sizeof(c)); if(n != sizeof(c)) printk("write_sigio_thread : " - "read failed, errno = %d\n", - errno); + "read failed, err = %d\n", -n); tmp = current_poll; current_poll = next_poll; next_poll = tmp; @@ -218,10 +210,10 @@ (fds->used - i) * sizeof(*fds->poll)); } - n = write(respond_fd, &c, sizeof(c)); + n = os_write_file(respond_fd, &c, sizeof(c)); if(n != sizeof(c)) printk("write_sigio_thread : write failed, " - "errno = %d\n", errno); + "err = %d\n", -n); } } } @@ -252,15 +244,15 @@ char c; flags = set_signals(0); - n = write(sigio_private[0], &c, sizeof(c)); + n = os_write_file(sigio_private[0], &c, sizeof(c)); if(n != sizeof(c)){ - printk("update_thread : write failed, errno = %d\n", errno); + printk("update_thread : write failed, err = %d\n", -n); goto fail; } - n = read(sigio_private[0], &c, sizeof(c)); + n = os_read_file(sigio_private[0], &c, sizeof(c)); if(n != sizeof(c)){ - printk("update_thread : read failed, errno = %d\n", errno); + printk("update_thread : read failed, err = %d\n", -n); goto fail; } @@ -271,10 +263,10 @@ if(write_sigio_pid != -1) os_kill_process(write_sigio_pid, 1); write_sigio_pid = -1; - close(sigio_private[0]); - close(sigio_private[1]); - close(write_sigio_fds[0]); - close(write_sigio_fds[1]); + os_close_file(sigio_private[0]); + os_close_file(sigio_private[1]); + os_close_file(write_sigio_fds[0]); + os_close_file(write_sigio_fds[1]); sigio_unlock(); set_signals(flags); } @@ -369,15 +361,15 @@ goto out; err = os_pipe(write_sigio_fds, 1, 1); - if(err){ + if(err < 0){ printk("write_sigio_workaround - os_pipe 1 failed, " - "errno = %d\n", -err); + "err = %d\n", -err); goto out; } err = os_pipe(sigio_private, 1, 1); - if(err){ + if(err < 0){ printk("write_sigio_workaround - os_pipe 2 failed, " - "errno = %d\n", -err); + "err = %d\n", -err); goto out_close1; } if(setup_initial_poll(sigio_private[1])) @@ -399,11 +391,11 @@ os_kill_process(write_sigio_pid, 1); write_sigio_pid = -1; out_close2: - close(sigio_private[0]); - close(sigio_private[1]); + os_close_file(sigio_private[0]); + os_close_file(sigio_private[1]); out_close1: - close(write_sigio_fds[0]); - close(write_sigio_fds[1]); + os_close_file(write_sigio_fds[0]); + os_close_file(write_sigio_fds[1]); sigio_unlock(); } @@ -412,10 +404,16 @@ int n; char c; - n = read(fd, &c, sizeof(c)); + n = os_read_file(fd, &c, sizeof(c)); if(n != sizeof(c)){ - printk("read_sigio_fd - read failed, errno = %d\n", errno); - return(-errno); + if(n < 0) { + printk("read_sigio_fd - read failed, err = %d\n", -n); + return(n); + } + else { + printk("read_sigio_fd - short read, bytes = %d\n", n); + return(-EIO); + } } return(n); } --- diff/arch/um/kernel/signal_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/signal_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -36,7 +36,7 @@ if(sig == SIGSEGV){ struct k_sigaction *ka; - ka = ¤t->sig->action[SIGSEGV - 1]; + ka = ¤t->sighand->action[SIGSEGV - 1]; ka->sa.sa_handler = SIG_DFL; } force_sig(SIGSEGV, current); @@ -60,10 +60,10 @@ int err, ret; ret = 0; + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; switch(error){ case -ERESTART_RESTARTBLOCK: - current_thread_info()->restart_block.fn = - do_no_restart_syscall; case -ERESTARTNOHAND: ret = -EINTR; break; @@ -142,7 +142,7 @@ return(0); /* Whee! Actually deliver the signal. */ - ka = ¤t->sig->action[sig -1 ]; + ka = ¤t->sighand->action[sig -1 ]; err = handle_signal(regs, sig, ka, &info, oldset, error); if(!err) return(1); @@ -201,7 +201,7 @@ } } -int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize) +int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) { sigset_t saveset, newset; @@ -227,20 +227,59 @@ } } +int sys_sigaction(int sig, const struct old_sigaction __user *act, + struct old_sigaction __user *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +int sys_sigaltstack(const stack_t *uss, stack_t *uoss) +{ + return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); +} + +extern int userspace_pid[]; + static int copy_sc_from_user(struct pt_regs *to, void *from, struct arch_frame_data *arch) { int ret; ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, arch), - copy_sc_from_user_skas(&to->regs, from)); + copy_sc_from_user_skas(userspace_pid[0], + &to->regs, from)); return(ret); } int sys_sigreturn(struct pt_regs regs) { - void *sc = sp_to_sc(PT_REGS_SP(¤t->thread.regs)); - void *mask = sp_to_mask(PT_REGS_SP(¤t->thread.regs)); + void __user *sc = sp_to_sc(PT_REGS_SP(¤t->thread.regs)); + void __user *mask = sp_to_mask(PT_REGS_SP(¤t->thread.regs)); int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); spin_lock_irq(¤t->sighand->siglock); @@ -257,8 +296,8 @@ int sys_rt_sigreturn(struct pt_regs regs) { - struct ucontext *uc = sp_to_uc(PT_REGS_SP(¤t->thread.regs)); - void *fp; + unsigned long sp = PT_REGS_SP(¤t->thread.regs); + struct ucontext __user *uc = sp_to_uc(sp); int sig_size = _NSIG_WORDS * sizeof(unsigned long); spin_lock_irq(¤t->sighand->siglock); @@ -266,7 +305,6 @@ sigdelsetmask(¤t->blocked, ~_BLOCKABLE); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - fp = (void *) (((unsigned long) uc) + sizeof(struct ucontext)); copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext, &signal_frame_si.common.arch); return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); --- diff/arch/um/kernel/skas/Makefile 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/skas/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -5,20 +5,24 @@ obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \ process_kern.o syscall_kern.o syscall_user.o time.o tlb.o trap_user.o \ - sys-$(SUBARCH)/ + uaccess.o sys-$(SUBARCH)/ + +host-progs := util/mk_ptregs +clean-files := include/skas_ptregs.h USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) -include/skas_ptregs.h : util/mk_ptregs - util/mk_ptregs > $@ - -util/mk_ptregs : - $(MAKE) -C util +$(TOPDIR)/arch/um/include/skas_ptregs.h : $(src)/util/mk_ptregs + @echo -n ' Generating $@' + @$< > $@.tmp + @if [ -r $@ ] && cmp -s $@ $@.tmp; then \ + echo ' (unchanged)'; \ + rm -f $@.tmp; \ + else \ + echo ' (updated)'; \ + mv -f $@.tmp $@; \ + fi $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean : - $(MAKE) -C util clean - $(RM) -f include/skas_ptregs.h --- diff/arch/um/kernel/skas/include/mode.h 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/skas/include/mode.h 2004-02-09 10:39:51.000000000 +0000 @@ -12,14 +12,16 @@ extern int have_fpx_regs; extern void user_time_init_skas(void); -extern int copy_sc_from_user_skas(union uml_pt_regs *regs, void *from_ptr); -extern int copy_sc_to_user_skas(void *to_ptr, void *fp, +extern int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, + void *from_ptr); +extern int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, union uml_pt_regs *regs, unsigned long fault_addr, int fault_type); extern void sig_handler_common_skas(int sig, void *sc_ptr); extern void halt_skas(void); extern void reboot_skas(void); extern void kill_off_processes_skas(void); +extern int is_skas_winch(int pid, int fd, void *data); #endif --- diff/arch/um/kernel/skas/include/skas.h 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/skas/include/skas.h 2004-02-09 10:39:51.000000000 +0000 @@ -8,7 +8,7 @@ #include "sysdep/ptrace.h" -extern int userspace_pid; +extern int userspace_pid[]; extern void switch_threads(void *me, void *next); extern void thread_wait(void *sw, void *fb); @@ -32,7 +32,7 @@ extern int new_mm(int from); extern void save_registers(union uml_pt_regs *regs); extern void restore_registers(union uml_pt_regs *regs); -extern void start_userspace(void); +extern void start_userspace(int cpu); extern void init_registers(int pid); #endif --- diff/arch/um/kernel/skas/include/uaccess.h 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/skas/include/uaccess.h 2004-02-09 10:39:51.000000000 +0000 @@ -6,20 +6,10 @@ #ifndef __SKAS_UACCESS_H #define __SKAS_UACCESS_H -#include "linux/string.h" -#include "linux/sched.h" -#include "linux/err.h" -#include "asm/processor.h" -#include "asm/pgtable.h" -#include "asm/errno.h" -#include "asm/current.h" -#include "asm/a.out.h" -#include "kern_util.h" - #define access_ok_skas(type, addr, size) \ ((segment_eq(get_fs(), KERNEL_DS)) || \ (((unsigned long) (addr) < TASK_SIZE) && \ - ((unsigned long) (addr) + (size) < TASK_SIZE))) + ((unsigned long) (addr) + (size) <= TASK_SIZE))) static inline int verify_area_skas(int type, const void * addr, unsigned long size) @@ -27,197 +17,12 @@ return(access_ok_skas(type, addr, size) ? 0 : -EFAULT); } -static inline unsigned long maybe_map(unsigned long virt, int is_write) -{ - pte_t pte; - - void *phys = um_virt_to_phys(current, virt, &pte); - int dummy_code; - - if(IS_ERR(phys) || (is_write && !pte_write(pte))){ - if(handle_page_fault(virt, 0, is_write, 0, &dummy_code)) - return(0); - phys = um_virt_to_phys(current, virt, NULL); - } - return((unsigned long) __va((unsigned long) phys)); -} - -static inline int buffer_op(unsigned long addr, int len, - int (*op)(unsigned long addr, int len, void *arg), - void *arg) -{ - int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len); - int remain = len, n; - - n = (*op)(addr, size, arg); - if(n != 0) - return(n < 0 ? remain : 0); - - addr += size; - remain -= size; - if(remain == 0) - return(0); - - while(addr < ((addr + remain) & PAGE_MASK)){ - n = (*op)(addr, PAGE_SIZE, arg); - if(n != 0) - return(n < 0 ? remain : 0); - - addr += PAGE_SIZE; - remain -= PAGE_SIZE; - } - if(remain == 0) - return(0); - - n = (*op)(addr, remain, arg); - if(n != 0) - return(n < 0 ? remain : 0); - return(0); -} - -static inline int copy_chunk_from_user(unsigned long from, int len, void *arg) -{ - unsigned long *to_ptr = arg, to = *to_ptr; - - from = maybe_map(from, 0); - if(from == 0) - return(-1); - - memcpy((void *) to, (void *) from, len); - *to_ptr += len; - return(0); -} - -static inline int copy_from_user_skas(void *to, const void *from, int n) -{ - if(segment_eq(get_fs(), KERNEL_DS)){ - memcpy(to, from, n); - return(0); - } - - return(access_ok_skas(VERIFY_READ, from, n) ? - buffer_op((unsigned long) from, n, copy_chunk_from_user, &to) : - n); -} - -static inline int copy_chunk_to_user(unsigned long to, int len, void *arg) -{ - unsigned long *from_ptr = arg, from = *from_ptr; - - to = maybe_map(to, 1); - if(to == 0) - return(-1); - - memcpy((void *) to, (void *) from, len); - *from_ptr += len; - return(0); -} - -static inline int copy_to_user_skas(void *to, const void *from, int n) -{ - if(segment_eq(get_fs(), KERNEL_DS)){ - memcpy(to, from, n); - return(0); - } - - return(access_ok_skas(VERIFY_WRITE, to, n) ? - buffer_op((unsigned long) to, n, copy_chunk_to_user, &from) : - n); -} - -static inline int strncpy_chunk_from_user(unsigned long from, int len, - void *arg) -{ - char **to_ptr = arg, *to = *to_ptr; - int n; - - from = maybe_map(from, 0); - if(from == 0) - return(-1); - - strncpy(to, (void *) from, len); - n = strnlen(to, len); - *to_ptr += n; - - if(n < len) - return(1); - return(0); -} - -static inline int strncpy_from_user_skas(char *dst, const char *src, int count) -{ - int n; - char *ptr = dst; - - if(segment_eq(get_fs(), KERNEL_DS)){ - strncpy(dst, src, count); - return(strnlen(dst, count)); - } - - if(!access_ok_skas(VERIFY_READ, src, 1)) - return(-EFAULT); - - n = buffer_op((unsigned long) src, count, strncpy_chunk_from_user, - &ptr); - if(n != 0) - return(-EFAULT); - return(strnlen(dst, count)); -} - -static inline int clear_chunk(unsigned long addr, int len, void *unused) -{ - addr = maybe_map(addr, 1); - if(addr == 0) - return(-1); - - memset((void *) addr, 0, len); - return(0); -} - -static inline int __clear_user_skas(void *mem, int len) -{ - return(buffer_op((unsigned long) mem, len, clear_chunk, NULL)); -} - -static inline int clear_user_skas(void *mem, int len) -{ - if(segment_eq(get_fs(), KERNEL_DS)){ - memset(mem, 0, len); - return(0); - } - - return(access_ok_skas(VERIFY_WRITE, mem, len) ? - buffer_op((unsigned long) mem, len, clear_chunk, NULL) : len); -} - -static inline int strnlen_chunk(unsigned long str, int len, void *arg) -{ - int *len_ptr = arg, n; - - str = maybe_map(str, 0); - if(str == 0) - return(-1); - - n = strnlen((void *) str, len); - *len_ptr += n; - - if(n < len) - return(1); - return(0); -} - -static inline int strnlen_user_skas(const void *str, int len) -{ - int count = 0, n; - - if(segment_eq(get_fs(), KERNEL_DS)) - return(strnlen(str, len) + 1); - - n = buffer_op((unsigned long) str, len, strnlen_chunk, &count); - if(n == 0) - return(count + 1); - return(-EFAULT); -} +extern int copy_from_user_skas(void *to, const void *from, int n); +extern int copy_to_user_skas(void *to, const void *from, int n); +extern int strncpy_from_user_skas(char *dst, const char *src, int count); +extern int __clear_user_skas(void *mem, int len); +extern int clear_user_skas(void *mem, int len); +extern int strnlen_user_skas(const void *str, int len); #endif --- diff/arch/um/kernel/skas/mem_user.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/skas/mem_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -7,6 +7,7 @@ #include #include #include "mem_user.h" +#include "mem.h" #include "user.h" #include "os.h" #include "proc_mm.h" @@ -15,12 +16,12 @@ int r, int w, int x) { struct proc_mm_op map; - struct mem_region *region; - int prot, n; + __u64 offset; + int prot, n, phys_fd; prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | (x ? PROT_EXEC : 0); - region = phys_region(phys); + phys_fd = phys_mapping(phys, &offset); map = ((struct proc_mm_op) { .op = MM_MMAP, .u = @@ -30,12 +31,12 @@ .prot = prot, .flags = MAP_SHARED | MAP_FIXED, - .fd = region->fd, - .offset = phys_offset(phys) + .fd = phys_fd, + .offset = offset } } } ); n = os_write_file(fd, &map, sizeof(map)); if(n != sizeof(map)) - printk("map : /proc/mm map failed, errno = %d\n", errno); + printk("map : /proc/mm map failed, err = %d\n", -n); } int unmap(int fd, void *addr, int len) @@ -49,8 +50,13 @@ { .addr = (unsigned long) addr, .len = len } } } ); n = os_write_file(fd, &unmap, sizeof(unmap)); - if((n != 0) && (n != sizeof(unmap))) - return(-errno); + if(n != sizeof(unmap)) { + if(n < 0) + return(n); + else if(n > 0) + return(-EIO); + } + return(0); } @@ -71,11 +77,15 @@ .prot = prot } } } ); n = os_write_file(fd, &protect, sizeof(protect)); - if((n != 0) && (n != sizeof(protect))){ + if(n != sizeof(protect)) { + if(n == 0) return(0); + if(must_succeed) - panic("protect failed, errno = %d", errno); - return(-errno); + panic("protect failed, err = %d", -n); + + return(-EIO); } + return(0); } --- diff/arch/um/kernel/skas/mmu.c 2003-01-02 10:43:05.000000000 +0000 +++ source/arch/um/kernel/skas/mmu.c 2004-02-09 10:39:51.000000000 +0000 @@ -22,9 +22,11 @@ else from = -1; mm->context.skas.mm_fd = new_mm(from); - if(mm->context.skas.mm_fd < 0) - panic("init_new_context_skas - new_mm failed, errno = %d\n", - mm->context.skas.mm_fd); + if(mm->context.skas.mm_fd < 0){ + printk("init_new_context_skas - new_mm failed, errno = %d\n", + mm->context.skas.mm_fd); + return(mm->context.skas.mm_fd); + } return(0); } --- diff/arch/um/kernel/skas/process.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/skas/process.c 2004-02-09 10:39:51.000000000 +0000 @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -24,6 +25,18 @@ #include "os.h" #include "proc_mm.h" #include "skas_ptrace.h" +#include "chan_user.h" + +int is_skas_winch(int pid, int fd, void *data) +{ + if(pid != getpid()) + return(0); + + register_winch_irq(-1, fd, -1, data); + return(1); +} + +/* These are set once at boot time and not changed thereafter */ unsigned long exec_regs[FRAME_SIZE]; unsigned long exec_fp_regs[HOST_FP_SIZE]; @@ -48,11 +61,11 @@ int err, syscall_nr, status; syscall_nr = PT_SYSCALL_NR(regs->skas.regs); + UPT_SYSCALL_NR(regs) = syscall_nr; if(syscall_nr < 1){ relay_signal(SIGTRAP, regs); return; } - UPT_SYSCALL_NR(regs) = syscall_nr; err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); if(err < 0) @@ -72,8 +85,6 @@ handle_syscall(regs); } -int userspace_pid; - static int userspace_tramp(void *arg) { init_new_thread_signals(0); @@ -83,7 +94,11 @@ return(0); } -void start_userspace(void) +/* Each element set once, and only accessed by a single processor anyway */ +#define NR_CPUS 1 +int userspace_pid[NR_CPUS]; + +void start_userspace(int cpu) { void *stack; unsigned long sp; @@ -114,21 +129,21 @@ if(munmap(stack, PAGE_SIZE) < 0) panic("start_userspace : munmap failed, errno = %d\n", errno); - userspace_pid = pid; + userspace_pid[cpu] = pid; } void userspace(union uml_pt_regs *regs) { - int err, status, op; + int err, status, op, pid = userspace_pid[0]; restore_registers(regs); - err = ptrace(PTRACE_SYSCALL, userspace_pid, 0, 0); + err = ptrace(PTRACE_SYSCALL, pid, 0, 0); if(err) panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", errno); while(1){ - err = waitpid(userspace_pid, &status, WUNTRACED); + err = waitpid(pid, &status, WUNTRACED); if(err < 0) panic("userspace - waitpid failed, errno = %d\n", errno); @@ -139,16 +154,17 @@ if(WIFSTOPPED(status)){ switch(WSTOPSIG(status)){ case SIGSEGV: - handle_segv(userspace_pid); + handle_segv(pid); break; case SIGTRAP: - handle_trap(userspace_pid, regs); + handle_trap(pid, regs); break; case SIGIO: case SIGVTALRM: case SIGILL: case SIGBUS: case SIGFPE: + case SIGWINCH: user_signal(WSTOPSIG(status), regs); break; default: @@ -162,7 +178,7 @@ op = singlestepping_skas() ? PTRACE_SINGLESTEP : PTRACE_SYSCALL; - err = ptrace(op, userspace_pid, 0, 0); + err = ptrace(op, pid, 0, 0); if(err) panic("userspace - PTRACE_SYSCALL failed, " "errno = %d\n", errno); @@ -177,7 +193,7 @@ *switch_buf_ptr = &switch_buf; *fork_buf_ptr = &fork_buf; - if(setjmp(fork_buf) == 0) + if(sigsetjmp(fork_buf, 1) == 0) new_thread_proc(stack, handler); remove_sigstack(); @@ -189,16 +205,16 @@ *switch_buf = &buf; fork_buf = fb; - if(setjmp(buf) == 0) - longjmp(*fork_buf, 1); + if(sigsetjmp(buf, 1) == 0) + siglongjmp(*fork_buf, 1); } -static int move_registers(int int_op, int fp_op, union uml_pt_regs *regs, - unsigned long *fp_regs) +static int move_registers(int pid, int int_op, int fp_op, + union uml_pt_regs *regs, unsigned long *fp_regs) { - if(ptrace(int_op, userspace_pid, 0, regs->skas.regs) < 0) + if(ptrace(int_op, pid, 0, regs->skas.regs) < 0) return(-errno); - if(ptrace(fp_op, userspace_pid, 0, fp_regs) < 0) + if(ptrace(fp_op, pid, 0, fp_regs) < 0) return(-errno); return(0); } @@ -217,10 +233,11 @@ fp_regs = regs->skas.fp; } - err = move_registers(PTRACE_GETREGS, fp_op, regs, fp_regs); + err = move_registers(userspace_pid[0], PTRACE_GETREGS, fp_op, regs, + fp_regs); if(err) panic("save_registers - saving registers failed, errno = %d\n", - err); + -err); } void restore_registers(union uml_pt_regs *regs) @@ -237,10 +254,11 @@ fp_regs = regs->skas.fp; } - err = move_registers(PTRACE_SETREGS, fp_op, regs, fp_regs); + err = move_registers(userspace_pid[0], PTRACE_SETREGS, fp_op, regs, + fp_regs); if(err) panic("restore_registers - saving registers failed, " - "errno = %d\n", err); + "errno = %d\n", -err); } void switch_threads(void *me, void *next) @@ -248,8 +266,8 @@ jmp_buf my_buf, **me_ptr = me, *next_buf = next; *me_ptr = &my_buf; - if(setjmp(my_buf) == 0) - longjmp(*next_buf, 1); + if(sigsetjmp(my_buf, 1) == 0) + siglongjmp(*next_buf, 1); } static jmp_buf initial_jmpbuf; @@ -265,14 +283,14 @@ int n; *fork_buf_ptr = &initial_jmpbuf; - n = setjmp(initial_jmpbuf); + n = sigsetjmp(initial_jmpbuf, 1); if(n == 0) new_thread_proc((void *) stack, new_thread_handler); else if(n == 1) remove_sigstack(); else if(n == 2){ (*cb_proc)(cb_arg); - longjmp(*cb_back, 1); + siglongjmp(*cb_back, 1); } else if(n == 3){ kmalloc_ok = 0; @@ -282,7 +300,7 @@ kmalloc_ok = 0; return(1); } - longjmp(**switch_buf, 1); + siglongjmp(**switch_buf, 1); } void remove_sigstack(void) @@ -304,8 +322,8 @@ cb_back = &here; block_signals(); - if(setjmp(here) == 0) - longjmp(initial_jmpbuf, 2); + if(sigsetjmp(here, 1) == 0) + siglongjmp(initial_jmpbuf, 2); unblock_signals(); cb_proc = NULL; @@ -316,22 +334,23 @@ void halt_skas(void) { block_signals(); - longjmp(initial_jmpbuf, 3); + siglongjmp(initial_jmpbuf, 3); } void reboot_skas(void) { block_signals(); - longjmp(initial_jmpbuf, 4); + siglongjmp(initial_jmpbuf, 4); } int new_mm(int from) { struct proc_mm_op copy; - int n, fd = os_open_file("/proc/mm", of_write(OPENFLAGS()), 0); + int n, fd = os_open_file("/proc/mm", + of_cloexec(of_write(OPENFLAGS())), 0); if(fd < 0) - return(-errno); + return(fd); if(from != -1){ copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, @@ -340,8 +359,9 @@ n = os_write_file(fd, ©, sizeof(copy)); if(n != sizeof(copy)) printk("new_mm : /proc/mm copy_segments failed, " - "errno = %d\n", errno); + "err = %d\n", -n); } + return(fd); } @@ -349,7 +369,8 @@ { int err; - err = ptrace(PTRACE_SWITCH_MM, userspace_pid, 0, mm_fd); +#warning need cpu pid in switch_mm_skas + err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd); if(err) panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n", errno); @@ -357,7 +378,8 @@ void kill_off_processes_skas(void) { - os_kill_process(userspace_pid, 1); +#warning need to loop over userspace_pids in kill_off_processes_skas + os_kill_process(userspace_pid[0], 1); } void init_registers(int pid) --- diff/arch/um/kernel/skas/process_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/skas/process_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -61,11 +61,13 @@ thread_wait(¤t->thread.mode.skas.switch_buf, current->thread.mode.skas.fork_buf); -#ifdef CONFIG_SMP - schedule_tail(NULL); -#endif + if(current->thread.prev_sched != NULL) + schedule_tail(current->thread.prev_sched); current->thread.prev_sched = NULL; + /* The return value is 1 if the kernel thread execs a process, + * 0 if it just exits + */ n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); if(n == 1) userspace(¤t->thread.regs.regs); @@ -93,9 +95,8 @@ current->thread.mode.skas.fork_buf); force_flush_all(); -#ifdef CONFIG_SMP - schedule_tail(current->thread.prev_sched); -#endif + if(current->thread.prev_sched != NULL) + schedule_tail(current->thread.prev_sched); current->thread.prev_sched = NULL; unblock_signals(); @@ -136,7 +137,7 @@ void init_idle_skas(void) { - cpu_tasks[current->thread_info->cpu].pid = os_getpid(); + cpu_tasks[current_thread->cpu].pid = os_getpid(); default_idle(); } @@ -160,11 +161,11 @@ int start_uml_skas(void) { - start_userspace(); + start_userspace(0); capture_signal_stack(); + uml_idle_timer(); init_new_thread_signals(1); - idle_timer(); init_task.thread.request.u.thread.proc = start_kernel_proc; init_task.thread.request.u.thread.arg = NULL; @@ -175,12 +176,14 @@ int external_pid_skas(struct task_struct *task) { - return(userspace_pid); +#warning Need to look up userspace_pid by cpu + return(userspace_pid[0]); } int thread_pid_skas(struct task_struct *task) { - return(userspace_pid); +#warning Need to look up userspace_pid by cpu + return(userspace_pid[0]); } /* --- diff/arch/um/kernel/skas/sys-i386/sigcontext.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/skas/sys-i386/sigcontext.c 2004-02-09 10:39:51.000000000 +0000 @@ -12,10 +12,9 @@ #include "kern_util.h" #include "user.h" #include "sigcontext.h" +#include "mode.h" -extern int userspace_pid; - -int copy_sc_from_user_skas(union uml_pt_regs *regs, void *from_ptr) +int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, void *from_ptr) { struct sigcontext sc, *from = from_ptr; unsigned long fpregs[FP_FRAME_SIZE]; @@ -41,13 +40,12 @@ regs->skas.regs[EIP] = sc.eip; regs->skas.regs[CS] = sc.cs; regs->skas.regs[EFL] = sc.eflags; - regs->skas.regs[UESP] = sc.esp_at_signal; regs->skas.regs[SS] = sc.ss; regs->skas.fault_addr = sc.cr2; regs->skas.fault_type = FAULT_WRITE(sc.err); regs->skas.trap_type = sc.trapno; - err = ptrace(PTRACE_SETFPREGS, userspace_pid, 0, fpregs); + err = ptrace(PTRACE_SETFPREGS, pid, 0, fpregs); if(err < 0){ printk("copy_sc_to_user - PTRACE_SETFPREGS failed, " "errno = %d\n", errno); @@ -57,8 +55,9 @@ return(0); } -int copy_sc_to_user_skas(void *to_ptr, void *fp, union uml_pt_regs *regs, - unsigned long fault_addr, int fault_type) +int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, + union uml_pt_regs *regs, unsigned long fault_addr, + int fault_type) { struct sigcontext sc, *to = to_ptr; struct _fpstate *to_fp; @@ -86,7 +85,7 @@ sc.err = TO_SC_ERR(fault_type); sc.trapno = regs->skas.trap_type; - err = ptrace(PTRACE_GETFPREGS, userspace_pid, 0, fpregs); + err = ptrace(PTRACE_GETFPREGS, pid, 0, fpregs); if(err < 0){ printk("copy_sc_to_user - PTRACE_GETFPREGS failed, " "errno = %d\n", errno); --- diff/arch/um/kernel/skas/syscall_kern.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/skas/syscall_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ --- diff/arch/um/kernel/skas/trap_user.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/skas/trap_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -41,8 +41,6 @@ { struct signal_info *info; - if(sig == SIGVTALRM) - missed_ticks[cpu()]++; regs->skas.is_user = 1; regs->skas.fault_addr = 0; regs->skas.fault_type = 0; --- diff/arch/um/kernel/skas/util/Makefile 2003-01-02 10:43:05.000000000 +0000 +++ source/arch/um/kernel/skas/util/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -1,10 +1,10 @@ all: mk_ptregs mk_ptregs : mk_ptregs.o - $(CC) -o mk_ptregs mk_ptregs.o + $(HOSTCC) -o mk_ptregs mk_ptregs.o mk_ptregs.o : mk_ptregs.c - $(CC) -c $< + $(HOSTCC) -c $< clean : $(RM) -f mk_ptregs *.o *~ --- diff/arch/um/kernel/skas/util/mk_ptregs.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/skas/util/mk_ptregs.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,3 +1,4 @@ +#include #include #include --- diff/arch/um/kernel/smp.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/um/kernel/smp.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,9 +1,15 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ #include "linux/config.h" +#include "linux/percpu.h" +#include "asm/pgalloc.h" +#include "asm/tlb.h" + +/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */ +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); #ifdef CONFIG_SMP @@ -23,7 +29,7 @@ #include "os.h" /* CPU online map, set by smp_boot_cpus */ -unsigned long cpu_online_map = cpumask_of_cpu(0); +unsigned long cpu_online_map = CPU_MASK_NONE; EXPORT_SYMBOL(cpu_online_map); @@ -55,7 +61,7 @@ void smp_send_reschedule(int cpu) { - write(cpu_data[cpu].ipi_pipe[1], "R", 1); + os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1); num_reschedules_sent++; } @@ -100,35 +106,34 @@ printk(KERN_INFO "Stopping all CPUs..."); for(i = 0; i < num_online_cpus(); i++){ - if(i == current->thread_info->cpu) + if(i == current_thread->cpu) continue; - write(cpu_data[i].ipi_pipe[1], "S", 1); + os_write_file(cpu_data[i].ipi_pipe[1], "S", 1); } printk("done\n"); } -static cpumask_t smp_commenced_mask; -static cpumask_t smp_callin_map = CPU_MASK_NONE; +static cpumask_t smp_commenced_mask = CPU_MASK_NONE; +static cpumask_t cpu_callin_map = CPU_MASK_NONE; static int idle_proc(void *cpup) { int cpu = (int) cpup, err; err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1); - if(err) - panic("CPU#%d failed to create IPI pipe, errno = %d", cpu, - -err); + if(err < 0) + panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err); activate_ipi(cpu_data[cpu].ipi_pipe[0], current->thread.mode.tt.extern_pid); wmb(); - if (cpu_test_and_set(cpu, &smp_callin_map)) { + if (cpu_test_and_set(cpu, cpu_callin_map)) { printk("huh, CPU#%d already present??\n", cpu); BUG(); } - while (!cpu_isset(cpu, &smp_commenced_mask)) + while (!cpu_isset(cpu, smp_commenced_mask)) cpu_relax(); cpu_set(cpu, cpu_online_map); @@ -143,16 +148,20 @@ current->thread.request.u.thread.proc = idle_proc; current->thread.request.u.thread.arg = (void *) cpu; - new_task = do_fork(CLONE_VM | CLONE_IDLETASK, 0, NULL, 0, NULL, NULL); - if(IS_ERR(new_task)) panic("do_fork failed in idle_thread"); + new_task = copy_process(CLONE_VM | CLONE_IDLETASK, 0, NULL, 0, NULL, + NULL); + if(IS_ERR(new_task)) + panic("copy_process failed in idle_thread, error = %ld", + PTR_ERR(new_task)); cpu_tasks[cpu] = ((struct cpu_task) { .pid = new_task->thread.mode.tt.extern_pid, .task = new_task } ); idle_threads[cpu] = new_task; - CHOOSE_MODE(write(new_task->thread.mode.tt.switch_pipe[1], &c, + CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c, sizeof(c)), ({ panic("skas mode doesn't support SMP"); })); + wake_up_forked_process(new_task); return(new_task); } @@ -160,15 +169,17 @@ { struct task_struct *idle; unsigned long waittime; - int err, cpu; + int err, cpu, me = smp_processor_id(); - cpu_set(0, cpu_online_map); - cpu_set(0, smp_callin_map); + cpu_clear(me, cpu_online_map); + cpu_set(me, cpu_online_map); + cpu_set(me, cpu_callin_map); - err = os_pipe(cpu_data[0].ipi_pipe, 1, 1); - if(err) panic("CPU#0 failed to create IPI pipe, errno = %d", -err); + err = os_pipe(cpu_data[me].ipi_pipe, 1, 1); + if(err < 0) + panic("CPU#0 failed to create IPI pipe, errno = %d", -err); - activate_ipi(cpu_data[0].ipi_pipe[0], + activate_ipi(cpu_data[me].ipi_pipe[0], current->thread.mode.tt.extern_pid); for(cpu = 1; cpu < ncpus; cpu++){ @@ -180,10 +191,10 @@ unhash_process(idle); waittime = 200000000; - while (waittime-- && !cpu_isset(cpu, smp_callin_map)) + while (waittime-- && !cpu_isset(cpu, cpu_callin_map)) cpu_relax(); - if (cpu_isset(cpu, smp_callin_map)) + if (cpu_isset(cpu, cpu_callin_map)) printk("done\n"); else printk("failed\n"); } @@ -216,7 +227,7 @@ int fd; fd = cpu_data[cpu].ipi_pipe[0]; - while (read(fd, &c, 1) == 1) { + while (os_read_file(fd, &c, 1) == 1) { switch (c) { case 'C': smp_call_function_slave(cpu); @@ -273,9 +284,9 @@ info = _info; for (i=0;ithread_info->cpu) && + if((i != current_thread->cpu) && cpu_isset(i, cpu_online_map)) - write(cpu_data[i].ipi_pipe[1], "C", 1); + os_write_file(cpu_data[i].ipi_pipe[1], "C", 1); while (atomic_read(&scf_started) != cpus) barrier(); --- diff/arch/um/kernel/sys_call_table.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/sys_call_table.c 2004-02-09 10:39:51.000000000 +0000 @@ -5,7 +5,6 @@ #include "linux/config.h" #include "linux/unistd.h" -#include "linux/version.h" #include "linux/sys.h" #include "linux/swap.h" #include "linux/sysctl.h" @@ -152,7 +151,6 @@ extern syscall_handler_t sys_munlockall; extern syscall_handler_t sys_sched_setparam; extern syscall_handler_t sys_sched_getparam; -extern syscall_handler_t sys_sched_setscheduler; extern syscall_handler_t sys_sched_getscheduler; extern syscall_handler_t sys_sched_get_priority_max; extern syscall_handler_t sys_sched_get_priority_min; @@ -219,15 +217,30 @@ extern syscall_handler_t sys_gettid; extern syscall_handler_t sys_readahead; extern syscall_handler_t sys_tkill; +extern syscall_handler_t sys_setxattr; +extern syscall_handler_t sys_lsetxattr; +extern syscall_handler_t sys_fsetxattr; +extern syscall_handler_t sys_getxattr; +extern syscall_handler_t sys_lgetxattr; +extern syscall_handler_t sys_fgetxattr; +extern syscall_handler_t sys_listxattr; +extern syscall_handler_t sys_llistxattr; +extern syscall_handler_t sys_flistxattr; +extern syscall_handler_t sys_removexattr; +extern syscall_handler_t sys_lremovexattr; +extern syscall_handler_t sys_fremovexattr; extern syscall_handler_t sys_sendfile64; extern syscall_handler_t sys_futex; extern syscall_handler_t sys_sched_setaffinity; extern syscall_handler_t sys_sched_getaffinity; +extern syscall_handler_t sys_set_thread_area; +extern syscall_handler_t sys_get_thread_area; extern syscall_handler_t sys_io_setup; extern syscall_handler_t sys_io_destroy; extern syscall_handler_t sys_io_getevents; extern syscall_handler_t sys_io_submit; extern syscall_handler_t sys_io_cancel; +extern syscall_handler_t sys_fadvise64; extern syscall_handler_t sys_exit_group; extern syscall_handler_t sys_lookup_dcookie; extern syscall_handler_t sys_epoll_create; @@ -235,6 +248,20 @@ extern syscall_handler_t sys_epoll_wait; extern syscall_handler_t sys_remap_file_pages; extern syscall_handler_t sys_set_tid_address; +extern syscall_handler_t sys_timer_create; +extern syscall_handler_t sys_timer_settime; +extern syscall_handler_t sys_timer_gettime; +extern syscall_handler_t sys_timer_getoverrun; +extern syscall_handler_t sys_timer_delete; +extern syscall_handler_t sys_clock_settime; +extern syscall_handler_t sys_clock_gettime; +extern syscall_handler_t sys_clock_getres; +extern syscall_handler_t sys_clock_nanosleep; +extern syscall_handler_t sys_statfs64; +extern syscall_handler_t sys_fstatfs64; +extern syscall_handler_t sys_tgkill; +extern syscall_handler_t sys_utimes; +extern syscall_handler_t sys_fadvise64_64; #ifdef CONFIG_NFSD #define NFSSERVCTL sys_nfsservctl @@ -246,7 +273,7 @@ extern syscall_handler_t um_time; extern syscall_handler_t um_stime; -#define LAST_GENERIC_SYSCALL __NR_set_tid_address +#define LAST_GENERIC_SYSCALL __NR_vserver #if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL #define LAST_SYSCALL LAST_GENERIC_SYSCALL @@ -413,7 +440,7 @@ [ __NR_munlockall ] = sys_munlockall, [ __NR_sched_setparam ] = sys_sched_setparam, [ __NR_sched_getparam ] = sys_sched_getparam, - [ __NR_sched_setscheduler ] = sys_sched_setscheduler, + [ __NR_sched_setscheduler ] = (syscall_handler_t *) sys_sched_setscheduler, [ __NR_sched_getscheduler ] = sys_sched_getscheduler, [ __NR_sched_yield ] = (syscall_handler_t *) yield, [ __NR_sched_get_priority_max ] = sys_sched_get_priority_max, @@ -455,32 +482,37 @@ [ __NR_stat64 ] = sys_stat64, [ __NR_lstat64 ] = sys_lstat64, [ __NR_fstat64 ] = sys_fstat64, - [ __NR_fcntl64 ] = sys_fcntl64, [ __NR_getdents64 ] = sys_getdents64, + [ __NR_fcntl64 ] = sys_fcntl64, + [ 223 ] = sys_ni_syscall, [ __NR_gettid ] = sys_gettid, [ __NR_readahead ] = sys_readahead, - [ __NR_setxattr ] = sys_ni_syscall, - [ __NR_lsetxattr ] = sys_ni_syscall, - [ __NR_fsetxattr ] = sys_ni_syscall, - [ __NR_getxattr ] = sys_ni_syscall, - [ __NR_lgetxattr ] = sys_ni_syscall, - [ __NR_fgetxattr ] = sys_ni_syscall, - [ __NR_listxattr ] = sys_ni_syscall, - [ __NR_llistxattr ] = sys_ni_syscall, - [ __NR_flistxattr ] = sys_ni_syscall, - [ __NR_removexattr ] = sys_ni_syscall, - [ __NR_lremovexattr ] = sys_ni_syscall, - [ __NR_fremovexattr ] = sys_ni_syscall, + [ __NR_setxattr ] = sys_setxattr, + [ __NR_lsetxattr ] = sys_lsetxattr, + [ __NR_fsetxattr ] = sys_fsetxattr, + [ __NR_getxattr ] = sys_getxattr, + [ __NR_lgetxattr ] = sys_lgetxattr, + [ __NR_fgetxattr ] = sys_fgetxattr, + [ __NR_listxattr ] = sys_listxattr, + [ __NR_llistxattr ] = sys_llistxattr, + [ __NR_flistxattr ] = sys_flistxattr, + [ __NR_removexattr ] = sys_removexattr, + [ __NR_lremovexattr ] = sys_lremovexattr, + [ __NR_fremovexattr ] = sys_fremovexattr, [ __NR_tkill ] = sys_tkill, [ __NR_sendfile64 ] = sys_sendfile64, [ __NR_futex ] = sys_futex, [ __NR_sched_setaffinity ] = sys_sched_setaffinity, [ __NR_sched_getaffinity ] = sys_sched_getaffinity, + [ __NR_set_thread_area ] = sys_ni_syscall, + [ __NR_get_thread_area ] = sys_ni_syscall, [ __NR_io_setup ] = sys_io_setup, [ __NR_io_destroy ] = sys_io_destroy, [ __NR_io_getevents ] = sys_io_getevents, [ __NR_io_submit ] = sys_io_submit, [ __NR_io_cancel ] = sys_io_cancel, + [ __NR_fadvise64 ] = sys_fadvise64, + [ 251 ] = sys_ni_syscall, [ __NR_exit_group ] = sys_exit_group, [ __NR_lookup_dcookie ] = sys_lookup_dcookie, [ __NR_epoll_create ] = sys_epoll_create, @@ -488,6 +520,21 @@ [ __NR_epoll_wait ] = sys_epoll_wait, [ __NR_remap_file_pages ] = sys_remap_file_pages, [ __NR_set_tid_address ] = sys_set_tid_address, + [ __NR_timer_create ] = sys_timer_create, + [ __NR_timer_settime ] = sys_timer_settime, + [ __NR_timer_gettime ] = sys_timer_gettime, + [ __NR_timer_getoverrun ] = sys_timer_getoverrun, + [ __NR_timer_delete ] = sys_timer_delete, + [ __NR_clock_settime ] = sys_clock_settime, + [ __NR_clock_gettime ] = sys_clock_gettime, + [ __NR_clock_getres ] = sys_clock_getres, + [ __NR_clock_nanosleep ] = sys_clock_nanosleep, + [ __NR_statfs64 ] = sys_statfs64, + [ __NR_fstatfs64 ] = sys_fstatfs64, + [ __NR_tgkill ] = sys_tgkill, + [ __NR_utimes ] = sys_utimes, + [ __NR_fadvise64_64 ] = sys_fadvise64_64, + [ __NR_vserver ] = sys_ni_syscall, ARCH_SYSCALLS [ LAST_SYSCALL + 1 ... NR_syscalls ] = --- diff/arch/um/kernel/syscall_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/syscall_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -35,39 +35,40 @@ long sys_fork(void) { - struct task_struct *p; + long ret; current->thread.forking = 1; - p = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL); + ret = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL); current->thread.forking = 0; - return(IS_ERR(p) ? PTR_ERR(p) : p->pid); + return(ret); } -long sys_clone(unsigned long clone_flags, unsigned long newsp) +long sys_clone(unsigned long clone_flags, unsigned long newsp, + int *parent_tid, int *child_tid) { - struct task_struct *p; + long ret; current->thread.forking = 1; - p = do_fork(clone_flags, newsp, NULL, 0, NULL, NULL); + ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid); current->thread.forking = 0; - return(IS_ERR(p) ? PTR_ERR(p) : p->pid); + return(ret); } long sys_vfork(void) { - struct task_struct *p; + long ret; current->thread.forking = 1; - p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, NULL); + ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, + NULL); current->thread.forking = 0; - return(IS_ERR(p) ? PTR_ERR(p) : p->pid); + return(ret); } /* common code for old and new mmaps */ -static inline long do_mmap2( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) +long do_mmap2(struct mm_struct *mm, unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, unsigned long fd, + unsigned long pgoff) { int error = -EBADF; struct file * file = NULL; @@ -79,9 +80,9 @@ goto out; } - down_write(¤t->mm->mmap_sem); + down_write(&mm->mmap_sem); error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); + up_write(&mm->mmap_sem); if (file) fput(file); @@ -93,7 +94,7 @@ unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) { - return do_mmap2(addr, len, prot, flags, fd, pgoff); + return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff); } /* @@ -120,7 +121,8 @@ if (offset & ~PAGE_MASK) goto out; - err = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + err = do_mmap2(current->mm, addr, len, prot, flags, fd, + offset >> PAGE_SHIFT); out: return err; } @@ -135,43 +137,12 @@ error = do_pipe(fd); if (!error) { - if (copy_to_user(fildes, fd, 2*sizeof(int))) + if (copy_to_user(fildes, fd, sizeof(fd))) error = -EFAULT; } return error; } -int sys_sigaction(int sig, const struct old_sigaction *act, - struct old_sigaction *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if (act) { - old_sigset_t mask; - if (verify_area(VERIFY_READ, act, sizeof(*act)) || - __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) - return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - - if (!ret && oact) { - if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) - return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } - - return ret; -} - /* * sys_ipc() is the de-multiplexer for the SysV IPC calls.. * @@ -253,7 +224,7 @@ return sys_shmctl (first, second, (struct shmid_ds *) ptr); default: - return -EINVAL; + return -ENOSYS; } } @@ -302,11 +273,6 @@ return error; } -int sys_sigaltstack(const stack_t *uss, stack_t *uoss) -{ - return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); -} - long execute_syscall(void *r) { return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r)); --- diff/arch/um/kernel/sysrq.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/um/kernel/sysrq.c 2004-02-09 10:39:51.000000000 +0000 @@ -55,6 +55,14 @@ show_trace((unsigned long *)esp); } +void show_stack(struct task_struct *task, unsigned long *sp) +{ + if(task) + show_trace_task(task); + else + show_trace(sp); +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically --- diff/arch/um/kernel/tempfile.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/tempfile.c 2004-02-09 10:39:51.000000000 +0000 @@ -28,6 +28,7 @@ } if((dir == NULL) || (*dir == '\0')) dir = "/tmp"; + tempdir = malloc(strlen(dir) + 2); if(tempdir == NULL){ fprintf(stderr, "Failed to malloc tempdir, " @@ -49,7 +50,8 @@ else *tempname = 0; strcat(tempname, template); - if((fd = mkstemp(tempname)) < 0){ + fd = mkstemp(tempname); + if(fd < 0){ fprintf(stderr, "open - cannot create %s: %s\n", tempname, strerror(errno)); return -1; @@ -59,7 +61,8 @@ return -1; } if(out_tempname){ - if((*out_tempname = strdup(tempname)) == NULL){ + *out_tempname = strdup(tempname); + if(*out_tempname == NULL){ perror("strdup"); return -1; } --- diff/arch/um/kernel/time.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/um/kernel/time.c 2004-02-09 10:39:51.000000000 +0000 @@ -4,24 +4,33 @@ */ #include +#include #include #include #include #include #include -#include "linux/module.h" #include "user_util.h" #include "kern_util.h" #include "user.h" #include "process.h" #include "signal_user.h" #include "time_user.h" +#include "kern_constants.h" + +/* XXX This really needs to be declared and initialized in a kernel file since + * it's in + */ +extern struct timespec wall_to_monotonic; extern struct timeval xtime; +struct timeval local_offset = { 0, 0 }; + void timer(void) { gettimeofday(&xtime, NULL); + timeradd(&xtime, &local_offset, &xtime); } void set_interval(int timer_type) @@ -66,7 +75,7 @@ errno); } -void idle_timer(void) +void uml_idle_timer(void) { if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR) panic("Couldn't unset SIGVTALRM handler"); @@ -76,14 +85,54 @@ set_interval(ITIMER_REAL); } +static unsigned long long get_host_hz(void) +{ + char mhzline[16], *end; + int ret, mult, mhz, rest, len; + + ret = cpu_feature("cpu MHz", mhzline, + sizeof(mhzline) / sizeof(mhzline[0])); + if(!ret) + panic ("Could not get host MHZ"); + + mhz = strtoul(mhzline, &end, 10); + + /* This business is to parse a floating point number without using + * floating types. + */ + + rest = 0; + mult = 0; + if(*end == '.'){ + end++; + len = strlen(end); + if(len < 6) + mult = 6 - len; + else if(len > 6) + end[6] = '\0'; + rest = strtoul(end, NULL, 10); + while(mult-- > 0) + rest *= 10; + } + + return(1000000 * mhz + rest); +} + +unsigned long long host_hz = 0; + void time_init(void) { + struct timespec now; + + host_hz = get_host_hz(); if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR) panic("Couldn't set SIGVTALRM handler"); set_interval(ITIMER_VIRTUAL); -} -struct timeval local_offset = { 0, 0 }; + do_posix_clock_monotonic_gettime(&now); + wall_to_monotonic.tv_sec = -now.tv_sec; + wall_to_monotonic.tv_nsec = -now.tv_nsec; +} void do_gettimeofday(struct timeval *tv) { @@ -95,15 +144,13 @@ time_unlock(flags); } -EXPORT_SYMBOL(do_gettimeofday); - int do_settimeofday(struct timespec *tv) { struct timeval now; unsigned long flags; struct timeval tv_in; - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) + if ((unsigned long) tv->tv_nsec >= UM_NSEC_PER_SEC) return -EINVAL; tv_in.tv_sec = tv->tv_sec; @@ -113,9 +160,9 @@ gettimeofday(&now, NULL); timersub(&tv_in, &now, &local_offset); time_unlock(flags); -} -EXPORT_SYMBOL(do_settimeofday); + return(0); +} void idle_sleep(int secs) { --- diff/arch/um/kernel/time_kern.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/um/kernel/time_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -30,6 +30,14 @@ return(HZ); } +/* + * Scheduler clock - returns current time in nanosec units. + */ +unsigned long long sched_clock(void) +{ + return (unsigned long long)jiffies_64 * (1000000000 / HZ); +} + /* Changed at early boot */ int timer_irq_inited = 0; @@ -39,13 +47,47 @@ */ int __attribute__ ((__section__ (".unprotected"))) missed_ticks[NR_CPUS]; +static int first_tick; +static unsigned long long prev_tsc; +static long long delta; /* Deviation per interval */ + +extern unsigned long long host_hz; + void timer_irq(union uml_pt_regs *regs) { - int cpu = current->thread_info->cpu, ticks = missed_ticks[cpu]; + unsigned long long ticks = 0; + + if(!timer_irq_inited){ + /* This is to ensure that ticks don't pile up when + * the timer handler is suspended */ + first_tick = 0; + return; + } + + if(first_tick){ +#if defined(CONFIG_UML_REAL_TIME_CLOCK) + unsigned long long tsc; + /* We've had 1 tick */ + tsc = time_stamp(); + + delta += tsc - prev_tsc; + prev_tsc = tsc; + + ticks += (delta * HZ) / host_hz; + delta -= (ticks * host_hz) / HZ; +#else + ticks = 1; +#endif + } + else { + prev_tsc = time_stamp(); + first_tick = 1; + } - if(!timer_irq_inited) return; - missed_ticks[cpu] = 0; - while(ticks--) do_IRQ(TIMER_IRQ, regs); + while(ticks > 0){ + do_IRQ(TIMER_IRQ, regs); + ticks--; + } } void boot_timer_handler(int sig) @@ -58,12 +100,13 @@ do_timer(®s); } -void um_timer(int irq, void *dev, struct pt_regs *regs) +irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs) { do_timer(regs); - write_seqlock(&xtime_lock); + write_seqlock_irq(&xtime_lock); timer(); - write_sequnlock(&xtime_lock); + write_sequnlock_irq(&xtime_lock); + return(IRQ_HANDLED); } long um_time(int * tloc) @@ -81,12 +124,12 @@ long um_stime(int * tptr) { int value; - struct timeval new; + struct timespec new; if (get_user(value, tptr)) return -EFAULT; new.tv_sec = value; - new.tv_usec = 0; + new.tv_nsec = 0; do_settimeofday(&new); return 0; } @@ -125,9 +168,11 @@ void timer_handler(int sig, union uml_pt_regs *regs) { #ifdef CONFIG_SMP + local_irq_disable(); update_process_times(user_context(UPT_SP(regs))); + local_irq_enable(); #endif - if(current->thread_info->cpu == 0) + if(current_thread->cpu == 0) timer_irq(regs); } @@ -136,6 +181,7 @@ unsigned long time_lock(void) { unsigned long flags; + spin_lock_irqsave(&timer_spinlock, flags); return(flags); } @@ -150,8 +196,8 @@ int err; CHOOSE_MODE(user_time_init_tt(), user_time_init_skas()); - if((err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", - NULL)) != 0) + err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL); + if(err != 0) printk(KERN_ERR "timer_init : request_irq failed - " "errno = %d\n", -err); timer_irq_inited = 1; @@ -160,7 +206,6 @@ __initcall(timer_init); - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically --- diff/arch/um/kernel/trap_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/trap_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -16,12 +16,15 @@ #include "asm/tlbflush.h" #include "asm/a.out.h" #include "asm/current.h" +#include "asm/irq.h" #include "user_util.h" #include "kern_util.h" #include "kern.h" #include "chan_kern.h" #include "mconsole_kern.h" #include "2_5compat.h" +#include "mem.h" +#include "mem_kern.h" int handle_page_fault(unsigned long address, unsigned long ip, int is_write, int is_user, int *code_out) @@ -51,12 +54,12 @@ if(is_write && !(vma->vm_flags & VM_WRITE)) goto out; page = address & PAGE_MASK; - if(page == (unsigned long) current->thread_info + PAGE_SIZE) + if(page == (unsigned long) current_thread + PAGE_SIZE) panic("Kernel stack overflow"); pgd = pgd_offset(mm, page); pmd = pmd_offset(pgd, page); - survive: do { + survive: switch (handle_mm_fault(mm, vma, address, is_write)){ case VM_FAULT_MINOR: current->min_flt++; @@ -71,14 +74,20 @@ err = -ENOMEM; goto out_of_memory; default: - BUG(); + if (current->pid == 1) { + up_read(&mm->mmap_sem); + yield(); + down_read(&mm->mmap_sem); + goto survive; + } + goto out; } pte = pte_offset_kernel(pmd, page); } while(!pte_present(*pte)); + err = 0; *pte = pte_mkyoung(*pte); if(pte_write(*pte)) *pte = pte_mkdirty(*pte); flush_tlb_page(vma, page); - err = 0; out: up_read(&mm->mmap_sem); return(err); @@ -98,6 +107,33 @@ goto out; } +LIST_HEAD(physmem_remappers); + +void register_remapper(struct remapper *info) +{ + list_add(&info->list, &physmem_remappers); +} + +static int check_remapped_addr(unsigned long address, int is_write) +{ + struct remapper *remapper; + struct list_head *ele; + __u64 offset; + int fd; + + fd = phys_mapping(__pa(address), &offset); + if(fd == -1) + return(0); + + list_for_each(ele, &physmem_remappers){ + remapper = list_entry(ele, struct remapper, list); + if((*remapper->proc)(fd, address, is_write, offset)) + return(1); + } + + return(0); +} + unsigned long segv(unsigned long address, unsigned long ip, int is_write, int is_user, void *sc) { @@ -109,7 +145,9 @@ flush_tlb_kernel_vm(); return(0); } - if(current->mm == NULL) + else if(check_remapped_addr(address & PAGE_MASK, is_write)) + return(0); + else if(current->mm == NULL) panic("Segfault with no mm"); err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); @@ -120,9 +158,8 @@ current->thread.fault_addr = (void *) address; do_longjmp(catcher, 1); } - else if(current->thread.fault_addr != NULL){ + else if(current->thread.fault_addr != NULL) panic("fault_addr set but no fault catcher"); - } else if(arch_fixup(ip, sc)) return(0); @@ -155,8 +192,6 @@ { struct siginfo si; - printk(KERN_ERR "Unfixable SEGV in '%s' (pid %d) at 0x%lx " - "(ip 0x%lx)\n", current->comm, current->pid, address, ip); si.si_signo = SIGSEGV; si.si_code = SEGV_ACCERR; si.si_addr = (void *) address; @@ -180,6 +215,11 @@ else relay_signal(sig, regs); } +void winch(int sig, union uml_pt_regs *regs) +{ + do_IRQ(WINCH_IRQ, regs); +} + void trap_init(void) { } --- diff/arch/um/kernel/trap_user.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/trap_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -5,11 +5,9 @@ #include #include -#include #include #include #include -#include #include #include #include @@ -82,6 +80,8 @@ .is_irq = 0 }, [ SIGILL ] { .handler = relay_signal, .is_irq = 0 }, + [ SIGWINCH ] { .handler = winch, + .is_irq = 1 }, [ SIGBUS ] { .handler = bus_handler, .is_irq = 0 }, [ SIGSEGV] { .handler = segv_handler, @@ -123,7 +123,7 @@ { jmp_buf *buf = b; - longjmp(*buf, val); + siglongjmp(*buf, val); } /* --- diff/arch/um/kernel/tt/Makefile 2003-05-21 11:49:50.000000000 +0100 +++ source/arch/um/kernel/tt/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -1,5 +1,5 @@ # -# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) # Licensed under the GPL # @@ -7,7 +7,7 @@ obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \ syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \ - uaccess_user.o sys-$(SUBARCH)/ + uaccess.o uaccess_user.o sys-$(SUBARCH)/ obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/ --- diff/arch/um/kernel/tt/exec_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/tt/exec_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -17,6 +17,7 @@ #include "mem_user.h" #include "os.h" #include "tlb.h" +#include "mode.h" static int exec_tramp(void *sig_stack) { @@ -47,17 +48,17 @@ do_exit(SIGKILL); } - if(current->thread_info->cpu == 0) + if(current_thread->cpu == 0) forward_interrupts(new_pid); current->thread.request.op = OP_EXEC; current->thread.request.u.exec.pid = new_pid; - unprotect_stack((unsigned long) current->thread_info); + unprotect_stack((unsigned long) current_thread); os_usr1_process(os_getpid()); enable_timer(); free_page(stack); protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); - task_protections((unsigned long) current->thread_info); + task_protections((unsigned long) current_thread); force_flush_all(); unblock_signals(); } --- diff/arch/um/kernel/tt/include/mode.h 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/tt/include/mode.h 2004-02-09 10:39:51.000000000 +0000 @@ -8,6 +8,8 @@ #include "sysdep/ptrace.h" +enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; + extern int tracing_pid; extern int tracer(int (*init_proc)(void *), void *sp); --- diff/arch/um/kernel/tt/include/uaccess.h 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/tt/include/uaccess.h 2004-02-09 10:39:51.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -43,65 +43,19 @@ extern int __do_copy_from_user(void *to, const void *from, int n, void **fault_addr, void **fault_catcher); - -static inline int copy_from_user_tt(void *to, const void *from, int n) -{ - return(access_ok_tt(VERIFY_READ, from, n) ? - __do_copy_from_user(to, from, n, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : n); -} - -static inline int copy_to_user_tt(void *to, const void *from, int n) -{ - return(access_ok_tt(VERIFY_WRITE, to, n) ? - __do_copy_to_user(to, from, n, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : n); -} - extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, void **fault_addr, void **fault_catcher); - -static inline int strncpy_from_user_tt(char *dst, const char *src, int count) -{ - int n; - - if(!access_ok_tt(VERIFY_READ, src, 1)) return(-EFAULT); - n = __do_strncpy_from_user(dst, src, count, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher); - if(n < 0) return(-EFAULT); - return(n); -} - extern int __do_clear_user(void *mem, size_t len, void **fault_addr, void **fault_catcher); - -static inline int __clear_user_tt(void *mem, int len) -{ - return(__do_clear_user(mem, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} - -static inline int clear_user_tt(void *mem, int len) -{ - return(access_ok_tt(VERIFY_WRITE, mem, len) ? - __do_clear_user(mem, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : len); -} - extern int __do_strnlen_user(const char *str, unsigned long n, void **fault_addr, void **fault_catcher); -static inline int strnlen_user_tt(const void *str, int len) -{ - return(__do_strnlen_user(str, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} +extern int copy_from_user_tt(void *to, const void *from, int n); +extern int copy_to_user_tt(void *to, const void *from, int n); +extern int strncpy_from_user_tt(char *dst, const char *src, int count); +extern int __clear_user_tt(void *mem, int len); +extern int clear_user_tt(void *mem, int len); +extern int strnlen_user_tt(const void *str, int len); #endif --- diff/arch/um/kernel/tt/mem_user.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/tt/mem_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -25,14 +25,13 @@ size = (unsigned long) segment_end - (unsigned long) segment_start; data = create_mem_file(size); - if((addr = mmap(NULL, size, PROT_WRITE | PROT_READ, - MAP_SHARED, data, 0)) == MAP_FAILED){ + addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0); + if(addr == MAP_FAILED){ perror("mapping new data segment"); exit(1); } memcpy(addr, segment_start, size); - if(switcheroo(data, prot, addr, segment_start, - size) < 0){ + if(switcheroo(data, prot, addr, segment_start, size) < 0){ printf("switcheroo failed\n"); exit(1); } --- diff/arch/um/kernel/tt/process_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/tt/process_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -62,7 +62,7 @@ reading = 0; err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); if(err != sizeof(c)) - panic("write of switch_pipe failed, errno = %d", -err); + panic("write of switch_pipe failed, err = %d", -err); reading = 1; if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD)) @@ -104,48 +104,72 @@ void release_thread_tt(struct task_struct *task) { - os_kill_process(task->thread.mode.tt.extern_pid, 0); + int pid = task->thread.mode.tt.extern_pid; + + if(os_getpid() != pid) + os_kill_process(pid, 0); } void exit_thread_tt(void) { - close(current->thread.mode.tt.switch_pipe[0]); - close(current->thread.mode.tt.switch_pipe[1]); + os_close_file(current->thread.mode.tt.switch_pipe[0]); + os_close_file(current->thread.mode.tt.switch_pipe[1]); } void schedule_tail(task_t *prev); static void new_thread_handler(int sig) { + unsigned long disable; int (*fn)(void *); void *arg; fn = current->thread.request.u.thread.proc; arg = current->thread.request.u.thread.arg; + UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1); + disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) | + (1 << (SIGIO - 1)) | (1 << (SIGPROF - 1)); + SC_SIGMASK(UPT_SC(¤t->thread.regs.regs)) &= ~disable; + suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); - block_signals(); + force_flush_all(); + if(current->thread.prev_sched != NULL) + schedule_tail(current->thread.prev_sched); + current->thread.prev_sched = NULL; + init_new_thread_signals(1); -#ifdef CONFIG_SMP - schedule_tail(current->thread.prev_sched); -#endif enable_timer(); free_page(current->thread.temp_stack); set_cmdline("(kernel thread)"); - force_flush_all(); - current->thread.prev_sched = NULL; change_sig(SIGUSR1, 1); change_sig(SIGVTALRM, 1); change_sig(SIGPROF, 1); - unblock_signals(); + local_irq_enable(); if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf)) do_exit(0); } static int new_thread_proc(void *stack) { + /* local_irq_disable is needed to block out signals until this thread is + * properly scheduled. Otherwise, the tracing thread will get mighty + * upset about any signals that arrive before that. + * This has the complication that it sets the saved signal mask in + * the sigcontext to block signals. This gets restored when this + * thread (or a descendant, since they get a copy of this sigcontext) + * returns to userspace. + * So, this is compensated for elsewhere. + * XXX There is still a small window until local_irq_disable() actually + * finishes where signals are possible - shouldn't be a problem in + * practice since SIGIO hasn't been forwarded here yet, and the + * local_irq_disable should finish before a SIGVTALRM has time to be + * delivered. + */ + + local_irq_disable(); init_new_thread_stack(stack, new_thread_handler); os_usr1_process(os_getpid()); return(0); @@ -156,7 +180,7 @@ * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off, * so it is blocked before it's called. They are re-enabled on sigreturn * despite the fact that they were blocked when the SIGUSR1 was issued because - * copy_thread copies the parent's signcontext, including the signal mask + * copy_thread copies the parent's sigcontext, including the signal mask * onto the signal frame. */ @@ -165,35 +189,32 @@ UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1); suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); -#ifdef CONFIG_SMP - schedule_tail(NULL); -#endif + force_flush_all(); + if(current->thread.prev_sched != NULL) + schedule_tail(current->thread.prev_sched); + current->thread.prev_sched = NULL; + enable_timer(); change_sig(SIGVTALRM, 1); local_irq_enable(); - force_flush_all(); if(current->mm != current->parent->mm) protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); - task_protections((unsigned long) current->thread_info); - - current->thread.prev_sched = NULL; + task_protections((unsigned long) current_thread); free_page(current->thread.temp_stack); + local_irq_disable(); change_sig(SIGUSR1, 0); set_user_mode(current); } -static int sigusr1 = SIGUSR1; - int fork_tramp(void *stack) { - int sig = sigusr1; - local_irq_disable(); + arch_init_thread(); init_new_thread_stack(stack, finish_fork_handler); - kill(os_getpid(), sig); + os_usr1_process(os_getpid()); return(0); } @@ -213,8 +234,8 @@ } err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1); - if(err){ - printk("copy_thread : pipe failed, errno = %d\n", -err); + if(err < 0){ + printk("copy_thread : pipe failed, err = %d\n", -err); return(err); } @@ -377,8 +398,8 @@ pages = (1 << CONFIG_KERNEL_STACK_ORDER); - start = (unsigned long) current->thread_info + PAGE_SIZE; - end = (unsigned long) current + PAGE_SIZE * pages; + start = (unsigned long) current_thread + PAGE_SIZE; + end = (unsigned long) current_thread + PAGE_SIZE * pages; protect_memory(uml_reserved, start - uml_reserved, 1, w, 1, 1); protect_memory(end, high_physmem - end, 1, w, 1, 1); @@ -454,8 +475,9 @@ init_task.thread.mode.tt.extern_pid = pid; err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1); - if(err) panic("Can't create switch pipe for init_task, errno = %d", - err); + if(err) + panic("Can't create switch pipe for init_task, errno = %d", + -err); } int singlestepping_tt(void *t) --- diff/arch/um/kernel/tt/ptproxy/proxy.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/tt/ptproxy/proxy.c 2004-02-09 10:39:51.000000000 +0000 @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -293,10 +292,10 @@ } char gdb_init_string[] = -"att 1 -b panic -b stop -handle SIGWINCH nostop noprint pass +"att 1 \n\ +b panic \n\ +b stop \n\ +handle SIGWINCH nostop noprint pass \n\ "; int start_debugger(char *prog, int startup, int stop, int *fd_out) @@ -304,7 +303,8 @@ int slave, child; slave = open_gdb_chan(); - if((child = fork()) == 0){ + child = fork(); + if(child == 0){ char *tempname = NULL; int fd; @@ -327,18 +327,19 @@ exit(1); #endif } - if((fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0)) < 0){ - printk("start_debugger : make_tempfile failed, errno = %d\n", - errno); + fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0); + if(fd < 0){ + printk("start_debugger : make_tempfile failed," + "err = %d\n", -fd); exit(1); } - write(fd, gdb_init_string, sizeof(gdb_init_string) - 1); + os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1); if(startup){ if(stop){ - write(fd, "b start_kernel\n", + os_write_file(fd, "b start_kernel\n", strlen("b start_kernel\n")); } - write(fd, "c\n", strlen("c\n")); + os_write_file(fd, "c\n", strlen("c\n")); } if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ printk("start_debugger : PTRACE_TRACEME failed, " --- diff/arch/um/kernel/tt/ptproxy/sysdep.c 2003-01-02 10:43:05.000000000 +0000 +++ source/arch/um/kernel/tt/ptproxy/sysdep.c 2004-02-09 10:39:51.000000000 +0000 @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include --- diff/arch/um/kernel/tt/ptproxy/wait.c 2003-01-02 10:43:05.000000000 +0000 +++ source/arch/um/kernel/tt/ptproxy/wait.c 2004-02-09 10:39:51.000000000 +0000 @@ -56,21 +56,23 @@ int real_wait_return(struct debugger *debugger) { unsigned long ip; - int err, pid; + int pid; pid = debugger->pid; + ip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0); ip = IP_RESTART_SYSCALL(ip); - err = ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip); + if(ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip) < 0) tracer_panic("real_wait_return : Failed to restart system " - "call, errno = %d\n"); + "call, errno = %d\n", errno); + if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) || (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || debugger_normal_return(debugger, -1)) tracer_panic("real_wait_return : gdb failed to wait, " - "errno = %d\n"); + "errno = %d\n", errno); return(0); } --- diff/arch/um/kernel/tt/syscall_kern.c 2003-02-26 16:01:01.000000000 +0000 +++ source/arch/um/kernel/tt/syscall_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ --- diff/arch/um/kernel/tt/tracer.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/tt/tracer.c 2004-02-09 10:39:51.000000000 +0000 @@ -39,16 +39,17 @@ return(0); register_winch_irq(tracer_winch[0], fd, -1, data); - return(0); + return(1); } static void tracer_winch_handler(int sig) { + int n; char c = 1; - if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c)) - printk("tracer_winch_handler - write failed, errno = %d\n", - errno); + n = os_write_file(tracer_winch[1], &c, sizeof(c)); + if(n != sizeof(c)) + printk("tracer_winch_handler - write failed, err = %d\n", -n); } /* Called only by the tracing thread during initialization */ @@ -58,9 +59,8 @@ int err; err = os_pipe(tracer_winch, 1, 1); - if(err){ - printk("setup_tracer_winch : os_pipe failed, errno = %d\n", - -err); + if(err < 0){ + printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err); return; } signal(SIGWINCH, tracer_winch_handler); @@ -130,8 +130,8 @@ case SIGTSTP: if(ptrace(PTRACE_CONT, pid, 0, sig) < 0) tracer_panic("sleeping_process_signal : Failed to " - "continue pid %d, errno = %d\n", pid, - sig); + "continue pid %d, signal = %d, " + "errno = %d\n", pid, sig, errno); break; /* This happens when the debugger (e.g. strace) is doing system call @@ -145,7 +145,7 @@ if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) tracer_panic("sleeping_process_signal : Failed to " "PTRACE_SYSCALL pid %d, errno = %d\n", - pid, sig); + pid, errno); break; case SIGSTOP: break; @@ -218,7 +218,7 @@ err = attach(debugger_parent); if(err){ printf("Failed to attach debugger parent %d, " - "errno = %d\n", debugger_parent, err); + "errno = %d\n", debugger_parent, -err); debugger_parent = -1; } else { @@ -233,7 +233,8 @@ } set_cmdline("(tracing thread)"); while(1){ - if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){ + pid = waitpid(-1, &status, WUNTRACED); + if(pid <= 0){ if(errno != ECHILD){ printf("wait failed - errno = %d\n", errno); } @@ -401,7 +402,7 @@ if(!strcmp(line, "go")) debug_stop = 0; else if(!strcmp(line, "parent")) debug_parent = 1; - else printk("Unknown debug option : '%s'\n", line); + else printf("Unknown debug option : '%s'\n", line); line = next; } --- diff/arch/um/kernel/tt/uaccess_user.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/tt/uaccess_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -8,15 +8,20 @@ #include #include "user_util.h" #include "uml_uaccess.h" +#include "task.h" +#include "kern_util.h" int __do_copy_from_user(void *to, const void *from, int n, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; unsigned long fault; int faulted; fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, __do_copy, &faulted); + TASK_REGS(get_current())->tt = save; + if(!faulted) return(0); else return(n - (fault - (unsigned long) from)); } @@ -29,11 +34,14 @@ int __do_strncpy_from_user(char *dst, const char *src, unsigned long count, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; unsigned long fault; int faulted; fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher, __do_strncpy, &faulted); + TASK_REGS(get_current())->tt = save; + if(!faulted) return(strlen(dst)); else return(-1); } @@ -46,11 +54,14 @@ int __do_clear_user(void *mem, unsigned long len, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; unsigned long fault; int faulted; fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher, __do_clear, &faulted); + TASK_REGS(get_current())->tt = save; + if(!faulted) return(0); else return(len - (fault - (unsigned long) mem)); } @@ -58,19 +69,20 @@ int __do_strnlen_user(const char *str, unsigned long n, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; int ret; unsigned long *faddrp = (unsigned long *)fault_addr; jmp_buf jbuf; *fault_catcher = &jbuf; - if(setjmp(jbuf) == 0){ + if(sigsetjmp(jbuf, 1) == 0) ret = strlen(str) + 1; - } - else { - ret = *faddrp - (unsigned long) str; - } + else ret = *faddrp - (unsigned long) str; + *fault_addr = NULL; *fault_catcher = NULL; + + TASK_REGS(get_current())->tt = save; return ret; } --- diff/arch/um/kernel/tt/unmap.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/tt/unmap.c 2004-02-09 10:39:51.000000000 +0000 @@ -3,10 +3,7 @@ * Licensed under the GPL */ -#include -#include #include -#include "user.h" int switcheroo(int fd, int prot, void *from, void *to, int size) { --- diff/arch/um/kernel/tty_log.c 2003-01-02 10:43:05.000000000 +0000 +++ source/arch/um/kernel/tty_log.c 2004-02-09 10:39:51.000000000 +0000 @@ -9,10 +9,10 @@ #include #include #include -#include #include #include "init.h" #include "user.h" +#include "kern_util.h" #include "os.h" #define TTY_LOG_DIR "./" @@ -24,29 +24,40 @@ #define TTY_LOG_OPEN 1 #define TTY_LOG_CLOSE 2 #define TTY_LOG_WRITE 3 +#define TTY_LOG_EXEC 4 + +#define TTY_READ 1 +#define TTY_WRITE 2 struct tty_log_buf { int what; unsigned long tty; int len; + int direction; + unsigned long sec; + unsigned long usec; }; -int open_tty_log(void *tty) +int open_tty_log(void *tty, void *current_tty) { struct timeval tv; struct tty_log_buf data; char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")]; int fd; + gettimeofday(&tv, NULL); if(tty_log_fd != -1){ - data = ((struct tty_log_buf) { what : TTY_LOG_OPEN, - tty : (unsigned long) tty, - len : 0 }); - write(tty_log_fd, &data, sizeof(data)); + data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN, + .tty = (unsigned long) tty, + .len = sizeof(current_tty), + .direction = 0, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); + os_write_file(tty_log_fd, ¤t_tty, data.len); return(tty_log_fd); } - gettimeofday(&tv, NULL); sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, (unsigned int) tv.tv_usec); @@ -62,30 +73,117 @@ void close_tty_log(int fd, void *tty) { struct tty_log_buf data; + struct timeval tv; if(tty_log_fd != -1){ - data = ((struct tty_log_buf) { what : TTY_LOG_CLOSE, - tty : (unsigned long) tty, - len : 0 }); - write(tty_log_fd, &data, sizeof(data)); + gettimeofday(&tv, NULL); + data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE, + .tty = (unsigned long) tty, + .len = 0, + .direction = 0, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); return; } - close(fd); + os_close_file(fd); } -int write_tty_log(int fd, char *buf, int len, void *tty) +static int log_chunk(int fd, const char *buf, int len) { + int total = 0, try, missed, n; + char chunk[64]; + + while(len > 0){ + try = (len > sizeof(chunk)) ? sizeof(chunk) : len; + missed = copy_from_user_proc(chunk, (char *) buf, try); + try -= missed; + n = os_write_file(fd, chunk, try); + if(n != try) { + if(n < 0) + return(n); + return(-EIO); + } + if(missed != 0) + return(-EFAULT); + + len -= try; + total += try; + buf += try; + } + + return(total); +} + +int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read) +{ + struct timeval tv; struct tty_log_buf data; + int direction; if(fd == tty_log_fd){ - data = ((struct tty_log_buf) { what : TTY_LOG_WRITE, - tty : (unsigned long) tty, - len : len }); - write(tty_log_fd, &data, sizeof(data)); + gettimeofday(&tv, NULL); + direction = is_read ? TTY_READ : TTY_WRITE; + data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE, + .tty = (unsigned long) tty, + .len = len, + .direction = direction, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); } - return(write(fd, buf, len)); + + return(log_chunk(fd, buf, len)); } +void log_exec(char **argv, void *tty) +{ + struct timeval tv; + struct tty_log_buf data; + char **ptr,*arg; + int len; + + if(tty_log_fd == -1) return; + + gettimeofday(&tv, NULL); + + len = 0; + for(ptr = argv; ; ptr++){ + if(copy_from_user_proc(&arg, ptr, sizeof(arg))) + return; + if(arg == NULL) break; + len += strlen_user_proc(arg); + } + + data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC, + .tty = (unsigned long) tty, + .len = len, + .direction = 0, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); + + for(ptr = argv; ; ptr++){ + if(copy_from_user_proc(&arg, ptr, sizeof(arg))) + return; + if(arg == NULL) break; + log_chunk(tty_log_fd, arg, strlen_user_proc(arg)); + } +} + +extern void register_tty_logger(int (*opener)(void *, void *), + int (*writer)(int, const char *, int, + void *, int), + void (*closer)(int, void *)); + +static int register_logger(void) +{ + register_tty_logger(open_tty_log, write_tty_log, close_tty_log); + return(0); +} + +__uml_initcall(register_logger); + static int __init set_tty_log_dir(char *name, int *add) { tty_log_dir = name; @@ -104,7 +202,7 @@ tty_log_fd = strtoul(name, &end, 0); if((*end != '\0') || (end == name)){ - printk("set_tty_log_fd - strtoul failed on '%s'\n", name); + printf("set_tty_log_fd - strtoul failed on '%s'\n", name); tty_log_fd = -1; } return 0; --- diff/arch/um/kernel/uaccess_user.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/uaccess_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -20,7 +20,7 @@ jmp_buf jbuf; *fault_catcher = &jbuf; - if(setjmp(jbuf) == 0){ + if(sigsetjmp(jbuf, 1) == 0){ (*op)(to, from, n); ret = 0; *faulted_out = 0; --- diff/arch/um/kernel/um_arch.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/um_arch.c 2004-02-09 10:39:51.000000000 +0000 @@ -38,13 +38,18 @@ #include "mode_kern.h" #include "mode.h" -#define DEFAULT_COMMAND_LINE "root=6200" +#define DEFAULT_COMMAND_LINE "root=98:0" struct cpuinfo_um boot_cpu_data = { .loops_per_jiffy = 0, .ipi_pipe = { -1, -1 } }; +/* Placeholder to make UML link until the vsyscall stuff is actually + * implemented + */ +void *__kernel_vsyscall; + unsigned long thread_saved_pc(struct task_struct *task) { return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, @@ -53,18 +58,22 @@ static int show_cpuinfo(struct seq_file *m, void *v) { - int index; + int index = 0; - index = (struct cpuinfo_um *)v - cpu_data; #ifdef CONFIG_SMP + index = (struct cpuinfo_um *) v - cpu_data; if (!cpu_online(index)) return 0; #endif - seq_printf(m, "bogomips\t: %lu.%02lu\n", + seq_printf(m, "processor\t: %d\n", index); + seq_printf(m, "vendor_id\t: User Mode Linux\n"); + seq_printf(m, "model name\t: UML\n"); + seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas")); + seq_printf(m, "host\t\t: %s\n", host_info); + seq_printf(m, "bogomips\t: %lu.%02lu\n\n", loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ)) % 100); - seq_printf(m, "host\t\t: %s\n", host_info); return(0); } @@ -134,12 +143,12 @@ if(umid != NULL){ snprintf(argv1_begin, (argv1_end - argv1_begin) * sizeof(*ptr), - "(%s)", umid); + "(%s) ", umid); ptr = &argv1_begin[strlen(argv1_begin)]; } else ptr = argv1_begin; - snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), " [%s]", cmd); + snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd); memset(argv1_begin + strlen(argv1_begin), '\0', argv1_end - argv1_begin - strlen(argv1_begin)); #endif @@ -179,7 +188,7 @@ static int __init uml_ncpus_setup(char *line, int *add) { if (!sscanf(line, "%d", &ncpus)) { - printk("Couldn't parse [%s]\n", line); + printf("Couldn't parse [%s]\n", line); return -1; } @@ -210,7 +219,7 @@ static int __init mode_tt_setup(char *line, int *add) { - printk("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n"); + printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n"); return(0); } @@ -221,7 +230,7 @@ static int __init mode_tt_setup(char *line, int *add) { - printk("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n"); + printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n"); return(0); } @@ -291,7 +300,7 @@ /* Set during early boot */ unsigned long brk_start; -static struct vm_reserved kernel_vm_reserved; +unsigned long end_iomem; #define MIN_VMALLOC (32 * 1024 * 1024) @@ -299,7 +308,7 @@ { unsigned long avail; unsigned long virtmem_size, max_physmem; - unsigned int i, add, err; + unsigned int i, add; for (i = 1; i < argc; i++){ if((i == 1) && (argv[i][0] == ' ')) continue; @@ -328,12 +337,16 @@ argv1_end = &argv[1][strlen(argv[1])]; #endif - set_usable_vm(uml_physmem, get_kmem_end()); - highmem = 0; - max_physmem = get_kmem_end() - uml_physmem - MIN_VMALLOC; - if(physmem_size > max_physmem){ - highmem = physmem_size - max_physmem; + iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; + max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC; + + /* Zones have to begin on a 1 << MAX_ORDER page boundary, + * so this makes sure that's true for highmem + */ + max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1); + if(physmem_size + iomem_size > max_physmem){ + highmem = physmem_size + iomem_size - max_physmem; physmem_size -= highmem; #ifndef CONFIG_HIGHMEM highmem = 0; @@ -343,11 +356,19 @@ } high_physmem = uml_physmem + physmem_size; - high_memory = (void *) high_physmem; + end_iomem = high_physmem + iomem_size; + high_memory = (void *) end_iomem; start_vm = VMALLOC_START; - setup_physmem(uml_physmem, uml_reserved, physmem_size); + setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); + if(init_maps(physmem_size, iomem_size, highmem)){ + printf("Failed to allocate mem_map for %ld bytes of physical " + "memory and %ld bytes of highmem\n", physmem_size, + highmem); + exit(1); + } + virtmem_size = physmem_size; avail = get_kmem_end() - start_vm; if(physmem_size > avail) virtmem_size = avail; @@ -357,18 +378,13 @@ printf("Kernel virtual memory size shrunk to %ld bytes\n", virtmem_size); - err = reserve_vm(high_physmem, end_vm, &kernel_vm_reserved); - if(err){ - printf("Failed to reserve VM area for kernel VM\n"); - exit(1); - } - uml_postsetup(); init_task.thread.kernel_stack = (unsigned long) &init_thread_info + 2 * PAGE_SIZE; task_protections((unsigned long) &init_thread_info); + os_flush_stdout(); return(CHOOSE_MODE(start_uml_tt(), start_uml_skas())); } @@ -376,8 +392,8 @@ static int panic_exit(struct notifier_block *self, unsigned long unused1, void *unused2) { -#ifdef CONFIG_SYSRQ - handle_sysrq('p', ¤t->thread.regs, NULL, NULL); +#ifdef CONFIG_MAGIC_SYSRQ + handle_sysrq('p', ¤t->thread.regs, NULL); #endif machine_halt(); return(0); @@ -403,6 +419,7 @@ arch_check_bugs(); check_ptrace(); check_sigio(); + check_devanon(); } /* --- diff/arch/um/kernel/umid.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/umid.c 2004-02-09 10:39:51.000000000 +0000 @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -33,18 +32,19 @@ static int umid_is_random = 1; static int umid_inited = 0; -static int make_umid(void); +static int make_umid(int (*printer)(const char *fmt, ...)); -static int __init set_umid(char *name, int is_random) +static int __init set_umid(char *name, int is_random, + int (*printer)(const char *fmt, ...)) { if(umid_inited){ - printk("Unique machine name can't be set twice\n"); + (*printer)("Unique machine name can't be set twice\n"); return(-1); } if(strlen(name) > UMID_LEN - 1) - printk("Unique machine name is being truncated to %s " - "characters\n", UMID_LEN); + (*printer)("Unique machine name is being truncated to %s " + "characters\n", UMID_LEN); strlcpy(umid, name, sizeof(umid)); umid_is_random = is_random; @@ -54,7 +54,7 @@ static int __init set_umid_arg(char *name, int *add) { - return(set_umid(name, 0)); + return(set_umid(name, 0, printf)); } __uml_setup("umid=", set_umid_arg, @@ -67,7 +67,7 @@ { int n; - if(!umid_inited && make_umid()) return(-1); + if(!umid_inited && make_umid(printk)) return(-1); n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1; if(n > len){ @@ -85,22 +85,23 @@ { char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; char pid[sizeof("nnnnn\0")]; - int fd; + int fd, n; if(umid_file_name("pid", file, sizeof(file))) return 0; fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))), 0644); if(fd < 0){ - printk("Open of machine pid file \"%s\" failed - " - "errno = %d\n", file, -fd); + printf("Open of machine pid file \"%s\" failed - " + "err = %d\n", file, -fd); return 0; } sprintf(pid, "%d\n", os_getpid()); - if(write(fd, pid, strlen(pid)) != strlen(pid)) - printk("Write of pid file failed - errno = %d\n", errno); - close(fd); + n = os_write_file(fd, pid, strlen(pid)); + if(n != strlen(pid)) + printf("Write of pid file failed - err = %d\n", -n); + os_close_file(fd); return 0; } @@ -111,7 +112,8 @@ int len; char file[256]; - if((directory = opendir(dir)) == NULL){ + directory = opendir(dir); + if(directory == NULL){ printk("actually_do_remove : couldn't open directory '%s', " "errno = %d\n", dir, errno); return(1); @@ -160,22 +162,24 @@ { char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; char pid[sizeof("nnnnn\0")], *end; - int dead, fd, p; + int dead, fd, p, n; sprintf(file, "%s/pid", dir); dead = 0; - if((fd = os_open_file(file, of_read(OPENFLAGS()), 0)) < 0){ + fd = os_open_file(file, of_read(OPENFLAGS()), 0); + if(fd < 0){ if(fd != -ENOENT){ printk("not_dead_yet : couldn't open pid file '%s', " - "errno = %d\n", file, -fd); + "err = %d\n", file, -fd); return(1); } dead = 1; } if(fd > 0){ - if(read(fd, pid, sizeof(pid)) < 0){ + n = os_read_file(fd, pid, sizeof(pid)); + if(n < 0){ printk("not_dead_yet : couldn't read pid file '%s', " - "errno = %d\n", file, errno); + "err = %d\n", file, -n); return(1); } p = strtoul(pid, &end, 0); @@ -197,7 +201,7 @@ if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){ uml_dir = malloc(strlen(name) + 1); if(uml_dir == NULL){ - printk("Failed to malloc uml_dir - error = %d\n", + printf("Failed to malloc uml_dir - error = %d\n", errno); uml_dir = name; return(0); @@ -217,7 +221,7 @@ char *home = getenv("HOME"); if(home == NULL){ - printk("make_uml_dir : no value in environment for " + printf("make_uml_dir : no value in environment for " "$HOME\n"); exit(1); } @@ -232,57 +236,59 @@ dir[len + 1] = '\0'; } - if((uml_dir = malloc(strlen(dir) + 1)) == NULL){ + uml_dir = malloc(strlen(dir) + 1); + if(uml_dir == NULL){ printf("make_uml_dir : malloc failed, errno = %d\n", errno); exit(1); } strcpy(uml_dir, dir); if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){ - printk("Failed to mkdir %s - errno = %i\n", uml_dir, errno); + printf("Failed to mkdir %s - errno = %i\n", uml_dir, errno); return(-1); } return 0; } -static int __init make_umid(void) +static int __init make_umid(int (*printer)(const char *fmt, ...)) { int fd, err; char tmp[strlen(uml_dir) + UMID_LEN + 1]; strlcpy(tmp, uml_dir, sizeof(tmp)); - if(*umid == 0){ + if(!umid_inited){ strcat(tmp, "XXXXXX"); fd = mkstemp(tmp); if(fd < 0){ - printk("make_umid - mkstemp failed, errno = %d\n", - errno); + (*printer)("make_umid - mkstemp failed, errno = %d\n", + errno); return(1); } - close(fd); + os_close_file(fd); /* There's a nice tiny little race between this unlink and * the mkdir below. It'd be nice if there were a mkstemp * for directories. */ unlink(tmp); - set_umid(&tmp[strlen(uml_dir)], 1); + set_umid(&tmp[strlen(uml_dir)], 1, printer); } sprintf(tmp, "%s%s", uml_dir, umid); - if((err = mkdir(tmp, 0777)) < 0){ + err = mkdir(tmp, 0777); + if(err < 0){ if(errno == EEXIST){ if(not_dead_yet(tmp)){ - printk("umid '%s' is in use\n", umid); + (*printer)("umid '%s' is in use\n", umid); return(-1); } err = mkdir(tmp, 0777); } } if(err < 0){ - printk("Failed to create %s - errno = %d\n", umid, errno); + (*printer)("Failed to create %s - errno = %d\n", umid, errno); return(-1); } @@ -295,7 +301,13 @@ ); __uml_postsetup(make_uml_dir); -__uml_postsetup(make_umid); + +static int __init make_umid_setup(void) +{ + return(make_umid(printf)); +} + +__uml_postsetup(make_umid_setup); __uml_postsetup(create_pid_file); /* --- diff/arch/um/kernel/user_syms.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/kernel/user_syms.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,7 +1,7 @@ #include #include -#include #include +#include #include #include #include @@ -27,7 +27,7 @@ #define __MODULE_STRING_1(x) #x #define __MODULE_STRING(x) __MODULE_STRING_1(x) -#if !defined(__AUTOCONF_INCLUDED__) +#if !defined(AUTOCONF_INCLUDED) #define __EXPORT_SYMBOL(sym,str) error config_must_be_included_before_module #define EXPORT_SYMBOL(var) error config_must_be_included_before_module --- diff/arch/um/kernel/user_util.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/kernel/user_util.c 2004-02-09 10:39:51.000000000 +0000 @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -82,7 +81,8 @@ int status, ret; while(1){ - if(((ret = waitpid(pid, &status, WUNTRACED)) < 0) || + ret = waitpid(pid, &status, WUNTRACED); + if((ret < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){ if(ret < 0){ if(errno == EINTR) continue; @@ -119,17 +119,6 @@ } } -int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags) -{ - int pid; - - pid = clone(fn, sp, flags, arg); - if(pid < 0) return(-1); - wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL); - ptrace(PTRACE_CONT, pid, 0, 0); - return(pid); -} - int raw(int fd, int complain) { struct termios tt; --- diff/arch/um/main.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/main.c 2004-02-09 10:39:51.000000000 +0000 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -123,12 +124,14 @@ set_stklim(); - if((new_argv = malloc((argc + 1) * sizeof(char *))) == NULL){ + new_argv = malloc((argc + 1) * sizeof(char *)); + if(new_argv == NULL){ perror("Mallocing argv"); exit(1); } for(i=0;i #include #include -#include #include #include #include @@ -42,13 +41,14 @@ { struct addr_change change; void *output; + int n; change.what = op; memcpy(change.addr, addr, sizeof(change.addr)); memcpy(change.netmask, netmask, sizeof(change.netmask)); - if(write(fd, &change, sizeof(change)) != sizeof(change)) - printk("etap_change - request failed, errno = %d\n", - errno); + n = os_write_file(fd, &change, sizeof(change)); + if(n != sizeof(change)) + printk("etap_change - request failed, err = %d\n", -n); output = um_kmalloc(page_size()); if(output == NULL) printk("etap_change : Failed to allocate output buffer\n"); @@ -82,15 +82,15 @@ struct etap_pre_exec_data *data = arg; dup2(data->control_remote, 1); - close(data->data_me); - close(data->control_me); + os_close_file(data->data_me); + os_close_file(data->control_me); } static int etap_tramp(char *dev, char *gate, int control_me, int control_remote, int data_me, int data_remote) { struct etap_pre_exec_data pe_data; - int pid, status, err; + int pid, status, err, n; char version_buf[sizeof("nnnnn\0")]; char data_fd_buf[sizeof("nnnnnn\0")]; char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; @@ -114,21 +114,21 @@ pe_data.data_me = data_me; pid = run_helper(etap_pre_exec, &pe_data, args, NULL); - if(pid < 0) err = errno; - close(data_remote); - close(control_remote); - if(read(control_me, &c, sizeof(c)) != sizeof(c)){ - printk("etap_tramp : read of status failed, errno = %d\n", - errno); - return(EINVAL); + if(pid < 0) err = pid; + os_close_file(data_remote); + os_close_file(control_remote); + n = os_read_file(control_me, &c, sizeof(c)); + if(n != sizeof(c)){ + printk("etap_tramp : read of status failed, err = %d\n", -n); + return(-EINVAL); } if(c != 1){ printk("etap_tramp : uml_net failed\n"); - err = EINVAL; - if(waitpid(pid, &status, 0) < 0) err = errno; - else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)){ + err = -EINVAL; + if(waitpid(pid, &status, 0) < 0) + err = -errno; + else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)) printk("uml_net didn't exit with status 1\n"); - } } return(err); } @@ -143,14 +143,14 @@ if(err) return(err); err = os_pipe(data_fds, 0, 0); - if(err){ - printk("data os_pipe failed - errno = %d\n", -err); + if(err < 0){ + printk("data os_pipe failed - err = %d\n", -err); return(err); } err = os_pipe(control_fds, 1, 0); - if(err){ - printk("control os_pipe failed - errno = %d\n", -err); + if(err < 0){ + printk("control os_pipe failed - err = %d\n", -err); return(err); } @@ -167,9 +167,9 @@ kfree(output); } - if(err != 0){ - printk("etap_tramp failed - errno = %d\n", err); - return(-err); + if(err < 0){ + printk("etap_tramp failed - err = %d\n", -err); + return(err); } pri->data_fd = data_fds[0]; @@ -183,11 +183,11 @@ struct ethertap_data *pri = data; iter_addresses(pri->dev, etap_close_addr, &pri->control_fd); - close(fd); + os_close_file(fd); os_shutdown_socket(pri->data_fd, 1, 1); - close(pri->data_fd); + os_close_file(pri->data_fd); pri->data_fd = -1; - close(pri->control_fd); + os_close_file(pri->control_fd); pri->control_fd = -1; } --- diff/arch/um/os-Linux/drivers/tuntap_user.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/os-Linux/drivers/tuntap_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -61,7 +60,7 @@ struct tuntap_pre_exec_data *data = arg; dup2(data->stdout, 1); - close(data->close_me); + os_close_file(data->close_me); } static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, @@ -86,7 +85,7 @@ if(pid < 0) return(-pid); - close(remote); + os_close_file(remote); msg.msg_name = NULL; msg.msg_namelen = 0; @@ -107,19 +106,19 @@ if(n < 0){ printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", errno); - return(errno); + return(-errno); } waitpid(pid, NULL, 0); cmsg = CMSG_FIRSTHDR(&msg); if(cmsg == NULL){ printk("tuntap_open_tramp : didn't receive a message\n"); - return(EINVAL); + return(-EINVAL); } if((cmsg->cmsg_level != SOL_SOCKET) || (cmsg->cmsg_type != SCM_RIGHTS)){ printk("tuntap_open_tramp : didn't receive a descriptor\n"); - return(EINVAL); + return(-EINVAL); } *fd_out = ((int *) CMSG_DATA(cmsg))[0]; return(0); @@ -133,27 +132,29 @@ int err, fds[2], len, used; err = tap_open_common(pri->dev, pri->gate_addr); - if(err) return(err); + if(err < 0) + return(err); if(pri->fixed_config){ - if((pri->fd = open("/dev/net/tun", O_RDWR)) < 0){ - printk("Failed to open /dev/net/tun, errno = %d\n", - errno); - return(-errno); + pri->fd = os_open_file("/dev/net/tun", of_rdwr(OPENFLAGS()), 0); + if(pri->fd < 0){ + printk("Failed to open /dev/net/tun, err = %d\n", + -pri->fd); + return(pri->fd); } memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TAP; + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name)); if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){ - printk("TUNSETIFF failed, errno = %d", errno); - close(pri->fd); + printk("TUNSETIFF failed, errno = %d\n", errno); + os_close_file(pri->fd); return(-errno); } } else { err = os_pipe(fds, 0, 0); - if(err){ - printk("tuntap_open : os_pipe failed - errno = %d\n", + if(err < 0){ + printk("tuntap_open : os_pipe failed - err = %d\n", -err); return(err); } @@ -166,19 +167,19 @@ fds[1], buffer, len, &used); output = buffer; - if(err == 0){ - pri->dev_name = uml_strdup(buffer); - output += IFNAMSIZ; - printk(output); - free_output_buffer(buffer); - } - else { - printk(output); + if(err < 0) { + printk("%s", output); free_output_buffer(buffer); - printk("tuntap_open_tramp failed - errno = %d\n", err); - return(-err); + printk("tuntap_open_tramp failed - err = %d\n", -err); + return(err); } - close(fds[0]); + + pri->dev_name = uml_strdup(buffer); + output += IFNAMSIZ; + printk("%s", output); + free_output_buffer(buffer); + + os_close_file(fds[0]); iter_addresses(pri->dev, open_addr, pri->dev_name); } @@ -191,7 +192,7 @@ if(!pri->fixed_config) iter_addresses(pri->dev, close_addr, pri->dev_name); - close(fd); + os_close_file(fd); pri->fd = -1; } --- diff/arch/um/os-Linux/file.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/os-Linux/file.c 2004-02-09 10:39:51.000000000 +0000 @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -17,33 +19,235 @@ #include "user.h" #include "kern_util.h" -int os_file_type(char *file) +static void copy_stat(struct uml_stat *dst, struct stat64 *src) +{ + *dst = ((struct uml_stat) { + .ust_dev = src->st_dev, /* device */ + .ust_ino = src->st_ino, /* inode */ + .ust_mode = src->st_mode, /* protection */ + .ust_nlink = src->st_nlink, /* number of hard links */ + .ust_uid = src->st_uid, /* user ID of owner */ + .ust_gid = src->st_gid, /* group ID of owner */ + .ust_size = src->st_size, /* total size, in bytes */ + .ust_blksize = src->st_blksize, /* blocksize for filesys I/O */ + .ust_blocks = src->st_blocks, /* number of blocks allocated */ + .ust_atime = src->st_atime, /* time of last access */ + .ust_mtime = src->st_mtime, /* time of last modification */ + .ust_ctime = src->st_ctime, /* time of last change */ + }); +} + +int os_stat_fd(const int fd, struct uml_stat *ubuf) +{ + struct stat64 sbuf; + int err; + + do { + err = fstat64(fd, &sbuf); + } while((err < 0) && (errno == EINTR)) ; + + if(err < 0) + return(-errno); + + if(ubuf != NULL) + copy_stat(ubuf, &sbuf); + return(err); +} + +int os_stat_file(const char *file_name, struct uml_stat *ubuf) +{ + struct stat64 sbuf; + int err; + + do { + err = stat64(file_name, &sbuf); + } while((err < 0) && (errno == EINTR)) ; + + if(err < 0) + return(-errno); + + if(ubuf != NULL) + copy_stat(ubuf, &sbuf); + return(err); +} + +int os_access(const char* file, int mode) +{ + int amode, err; + + amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) | + (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ; + + err = access(file, amode); + if(err < 0) + return(-errno); + + return(0); +} + +void os_print_error(int error, const char* str) +{ + errno = error < 0 ? -error : error; + + perror(str); +} + +/* FIXME? required only by hostaudio (because it passes ioctls verbatim) */ +int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg) +{ + int err; + + err = ioctl(fd, cmd, arg); + if(err < 0) + return(-errno); + + return(err); +} + +int os_window_size(int fd, int *rows, int *cols) +{ + struct winsize size; + + if(ioctl(fd, TIOCGWINSZ, &size) < 0) + return(-errno); + + *rows = size.ws_row; + *cols = size.ws_col; + + return(0); +} + +int os_new_tty_pgrp(int fd, int pid) { - struct stat64 buf; + if(ioctl(fd, TIOCSCTTY, 0) < 0){ + printk("TIOCSCTTY failed, errno = %d\n", errno); + return(-errno); + } + + if(tcsetpgrp(fd, pid) < 0){ + printk("tcsetpgrp failed, errno = %d\n", errno); + return(-errno); + } + + return(0); +} + +/* FIXME: ensure namebuf in os_get_if_name is big enough */ +int os_get_ifname(int fd, char* namebuf) +{ + if(ioctl(fd, SIOCGIFNAME, namebuf) < 0) + return(-errno); + + return(0); +} + +int os_set_slip(int fd) +{ + int disc, sencap; + + disc = N_SLIP; + if(ioctl(fd, TIOCSETD, &disc) < 0){ + printk("Failed to set slip line discipline - " + "errno = %d\n", errno); + return(-errno); + } + + sencap = 0; + if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0){ + printk("Failed to set slip encapsulation - " + "errno = %d\n", errno); + return(-errno); + } + + return(0); +} + +int os_set_owner(int fd, int pid) +{ + if(fcntl(fd, F_SETOWN, pid) < 0){ + int save_errno = errno; + + if(fcntl(fd, F_GETOWN, 0) != pid) + return(-save_errno); + } + + return(0); +} + +/* FIXME? moved wholesale from sigio_user.c to get fcntls out of that file */ +int os_sigio_async(int master, int slave) +{ + int flags; - if(stat64(file, &buf) == -1) + flags = fcntl(master, F_GETFL); + if(flags < 0) { + printk("fcntl F_GETFL failed, errno = %d\n", errno); return(-errno); + } + + if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || + (fcntl(master, F_SETOWN, os_getpid()) < 0)){ + printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n", errno); + return(-errno); + } + + if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)){ + printk("fcntl F_SETFL failed, errno = %d\n", errno); + return(-errno); + } - if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR); - else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK); - else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV); - else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV); - else if(S_ISFIFO(buf.st_mode)) return(OS_TYPE_FIFO); - else if(S_ISSOCK(buf.st_mode)) return(OS_TYPE_SOCK); + return(0); +} + +int os_mode_fd(int fd, int mode) +{ + int err; + + do { + err = fchmod(fd, mode); + } while((err < 0) && (errno==EINTR)) ; + + if(err < 0) + return(-errno); + + return(0); +} + +int os_file_type(char *file) +{ + struct uml_stat buf; + int err; + + err = os_stat_file(file, &buf); + if(err < 0) + return(err); + + if(S_ISDIR(buf.ust_mode)) return(OS_TYPE_DIR); + else if(S_ISLNK(buf.ust_mode)) return(OS_TYPE_SYMLINK); + else if(S_ISCHR(buf.ust_mode)) return(OS_TYPE_CHARDEV); + else if(S_ISBLK(buf.ust_mode)) return(OS_TYPE_BLOCKDEV); + else if(S_ISFIFO(buf.ust_mode)) return(OS_TYPE_FIFO); + else if(S_ISSOCK(buf.ust_mode)) return(OS_TYPE_SOCK); else return(OS_TYPE_FILE); } int os_file_mode(char *file, struct openflags *mode_out) { + int err; + *mode_out = OPENFLAGS(); - if(!access(file, W_OK)) *mode_out = of_write(*mode_out); - else if(errno != EACCES) - return(-errno); + err = os_access(file, OS_ACC_W_OK); + if((err < 0) && (err != -EACCES)) + return(err); - if(!access(file, R_OK)) *mode_out = of_read(*mode_out); - else if(errno != EACCES) - return(-errno); + *mode_out = of_write(*mode_out); + + err = os_access(file, OS_ACC_R_OK); + if((err < 0) && (err != -EACCES)) + return(err); + + *mode_out = of_read(*mode_out); return(0); } @@ -63,16 +267,14 @@ if(flags.e) f |= O_EXCL; fd = open64(file, f, mode); - if(fd < 0) return(-errno); - - if(flags.cl){ - if(fcntl(fd, F_SETFD, 1)){ - close(fd); - return(-errno); - } + if(fd < 0) + return(-errno); + + if(flags.cl && fcntl(fd, F_SETFD, 1)){ + os_close_file(fd); + return(-errno); } - return(fd); return(fd); } @@ -90,7 +292,7 @@ err = connect(fd, (struct sockaddr *) &sock, sizeof(sock)); if(err) - return(err); + return(-errno); return(fd); } @@ -109,88 +311,162 @@ return(0); } -int os_read_file(int fd, void *buf, int len) +static int fault_buffer(void *start, int len, + int (*copy_proc)(void *addr, void *buf, int len)) { - int n; + int page = getpagesize(), i; + char c; - /* Force buf into memory if it's not already. */ + for(i = 0; i < len; i += page){ + if((*copy_proc)(start + i, &c, sizeof(c))) + return(-EFAULT); + } + if((len % page) != 0){ + if((*copy_proc)(start + len - 1, &c, sizeof(c))) + return(-EFAULT); + } + return(0); +} - /* XXX This fails if buf is kernel memory */ -#ifdef notdef - if(copy_to_user_proc(buf, &c, sizeof(c))) - return(-EFAULT); -#endif +static int file_io(int fd, void *buf, int len, + int (*io_proc)(int fd, void *buf, int len), + int (*copy_user_proc)(void *addr, void *buf, int len)) +{ + int n, err; + + do { + n = (*io_proc)(fd, buf, len); + if((n < 0) && (errno == EFAULT)){ + err = fault_buffer(buf, len, copy_user_proc); + if(err) + return(err); + n = (*io_proc)(fd, buf, len); + } + } while((n < 0) && (errno == EINTR)); - n = read(fd, buf, len); if(n < 0) return(-errno); return(n); } -int os_write_file(int fd, void *buf, int count) +int os_read_file(int fd, void *buf, int len) { - int n; - - /* Force buf into memory if it's not already. */ - - /* XXX This fails if buf is kernel memory */ -#ifdef notdef - if(copy_to_user_proc(buf, buf, buf[0])) - return(-EFAULT); -#endif + return(file_io(fd, buf, len, (int (*)(int, void *, int)) read, + copy_from_user_proc)); +} - n = write(fd, buf, count); - if(n < 0) - return(-errno); - return(n); +int os_write_file(int fd, const void *buf, int len) +{ + return(file_io(fd, (void *) buf, len, + (int (*)(int, void *, int)) write, copy_to_user_proc)); } int os_file_size(char *file, long long *size_out) { - struct stat64 buf; + struct uml_stat buf; + int err; - if(stat64(file, &buf) == -1){ - printk("Couldn't stat \"%s\" : errno = %d\n", file, errno); - return(-errno); + err = os_stat_file(file, &buf); + if(err < 0){ + printk("Couldn't stat \"%s\" : err = %d\n", file, -err); + return(err); } - if(S_ISBLK(buf.st_mode)){ + + if(S_ISBLK(buf.ust_mode)){ int fd, blocks; - if((fd = open64(file, O_RDONLY)) < 0){ - printk("Couldn't open \"%s\", errno = %d\n", file, - errno); - return(-errno); + fd = os_open_file(file, of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Couldn't open \"%s\", errno = %d\n", file, -fd); + return(fd); } if(ioctl(fd, BLKGETSIZE, &blocks) < 0){ printk("Couldn't get the block size of \"%s\", " "errno = %d\n", file, errno); - close(fd); - return(-errno); + err = -errno; + os_close_file(fd); + return(err); } *size_out = ((long long) blocks) * 512; - close(fd); + os_close_file(fd); return(0); } - *size_out = buf.st_size; + *size_out = buf.ust_size; + return(0); +} + +int os_file_modtime(char *file, unsigned long *modtime) +{ + struct uml_stat buf; + int err; + + err = os_stat_file(file, &buf); + if(err < 0){ + printk("Couldn't stat \"%s\" : err = %d\n", file, -err); + return(err); + } + + *modtime = buf.ust_mtime; return(0); } +int os_get_exec_close(int fd, int* close_on_exec) +{ + int ret; + + do { + ret = fcntl(fd, F_GETFD); + } while((ret < 0) && (errno == EINTR)) ; + + if(ret < 0) + return(-errno); + + *close_on_exec = (ret&FD_CLOEXEC) ? 1 : 0; + return(ret); +} + +int os_set_exec_close(int fd, int close_on_exec) +{ + int flag, err; + + if(close_on_exec) flag = FD_CLOEXEC; + else flag = 0; + + do { + err = fcntl(fd, F_SETFD, flag); + } while((err < 0) && (errno == EINTR)) ; + + if(err < 0) + return(-errno); + return(err); +} + int os_pipe(int *fds, int stream, int close_on_exec) { int err, type = stream ? SOCK_STREAM : SOCK_DGRAM; err = socketpair(AF_UNIX, type, 0, fds); - if(err) + if(err < 0) return(-errno); if(!close_on_exec) return(0); - if((fcntl(fds[0], F_SETFD, 1) < 0) || (fcntl(fds[1], F_SETFD, 1) < 0)) - printk("os_pipe : Setting FD_CLOEXEC failed, errno = %d", - errno); + err = os_set_exec_close(fds[0], 1); + if(err < 0) + goto error; + + err = os_set_exec_close(fds[1], 1); + if(err < 0) + goto error; return(0); + + error: + printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err); + os_close_file(fds[1]); + os_close_file(fds[0]); + return(err); } int os_set_fd_async(int fd, int owner) @@ -270,7 +546,7 @@ return(-EINVAL); } err = shutdown(fd, what); - if(err) + if(err < 0) return(-errno); return(0); } @@ -315,7 +591,7 @@ return(new); } -int create_unix_socket(char *file, int len) +int os_create_unix_socket(char *file, int len, int close_on_exec) { struct sockaddr_un addr; int sock, err; @@ -327,6 +603,13 @@ return(-errno); } + if(close_on_exec) { + err = os_set_exec_close(sock, 1); + if(err < 0) + printk("create_unix_socket : close_on_exec failed, " + "err = %d", -err); + } + addr.sun_family = AF_UNIX; /* XXX Be more careful about overflow */ @@ -334,14 +617,45 @@ err = bind(sock, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0){ - printk("create_listening_socket - bind failed, errno = %d\n", - errno); + printk("create_listening_socket at '%s' - bind failed, " + "errno = %d\n", file, errno); return(-errno); } return(sock); } +void os_flush_stdout(void) +{ + fflush(stdout); +} + +int os_lock_file(int fd, int excl) +{ + int type = excl ? F_WRLCK : F_RDLCK; + struct flock lock = ((struct flock) { .l_type = type, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 0 } ); + int err, save; + + err = fcntl(fd, F_SETLK, &lock); + if(!err) + goto out; + + save = -errno; + err = fcntl(fd, F_GETLK, &lock); + if(err){ + err = -errno; + goto out; + } + + printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid); + err = save; + out: + return(err); +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically --- diff/arch/um/os-Linux/process.c 2003-02-13 11:46:50.000000000 +0000 +++ source/arch/um/os-Linux/process.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -7,32 +7,37 @@ #include #include #include +#include #include #include #include "os.h" #include "user.h" +#define ARBITRARY_ADDR -1 +#define FAILURE_PID -1 + unsigned long os_process_pc(int pid) { char proc_stat[sizeof("/proc/#####/stat\0")], buf[256]; unsigned long pc; - int fd; + int fd, err; sprintf(proc_stat, "/proc/%d/stat", pid); fd = os_open_file(proc_stat, of_read(OPENFLAGS()), 0); if(fd < 0){ - printk("os_process_pc - couldn't open '%s', errno = %d\n", - proc_stat, errno); - return(-1); + printk("os_process_pc - couldn't open '%s', err = %d\n", + proc_stat, -fd); + return(ARBITRARY_ADDR); } - if(read(fd, buf, sizeof(buf)) < 0){ - printk("os_process_pc - couldn't read '%s', errno = %d\n", - proc_stat, errno); - close(fd); - return(-1); + err = os_read_file(fd, buf, sizeof(buf)); + if(err < 0){ + printk("os_process_pc - couldn't read '%s', err = %d\n", + proc_stat, -err); + os_close_file(fd); + return(ARBITRARY_ADDR); } - close(fd); - pc = -1; + os_close_file(fd); + pc = ARBITRARY_ADDR; if(sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " "%*d %*d %*d %*d %ld", &pc) != 1){ @@ -52,22 +57,23 @@ snprintf(stat, sizeof(stat), "/proc/%d/stat", pid); fd = os_open_file(stat, of_read(OPENFLAGS()), 0); if(fd < 0){ - printk("Couldn't open '%s', errno = %d\n", stat, -fd); - return(-1); + printk("Couldn't open '%s', err = %d\n", stat, -fd); + return(FAILURE_PID); } - n = read(fd, data, sizeof(data)); - close(fd); + n = os_read_file(fd, data, sizeof(data)); + os_close_file(fd); if(n < 0){ - printk("Couldn't read '%s', errno = %d\n", stat); - return(-1); + printk("Couldn't read '%s', err = %d\n", stat, -n); + return(FAILURE_PID); } - parent = -1; + parent = FAILURE_PID; /* XXX This will break if there is a space in the command */ n = sscanf(data, "%*d %*s %*c %d", &parent); - if(n != 1) printk("Failed to scan '%s'\n", data); + if(n != 1) + printk("Failed to scan '%s'\n", data); return(parent); } @@ -87,7 +93,8 @@ void os_usr1_process(int pid) { - kill(pid, SIGUSR1); + syscall(__NR_tkill, pid, SIGUSR1); + /* kill(pid, SIGUSR1); */ } int os_getpid(void) @@ -95,7 +102,7 @@ return(getpid()); } -int os_map_memory(void *virt, int fd, unsigned long off, unsigned long len, +int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, int r, int w, int x) { void *loc; @@ -104,8 +111,8 @@ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | (x ? PROT_EXEC : 0); - loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, - fd, off); + loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, + fd, off); if(loc == MAP_FAILED) return(-errno); return(0); @@ -126,7 +133,8 @@ int err; err = munmap(addr, len); - if(err < 0) return(-errno); + if(err < 0) + return(-errno); return(0); } --- diff/arch/um/os-Linux/tty.c 2003-01-02 10:43:05.000000000 +0000 +++ source/arch/um/os-Linux/tty.c 2004-02-09 10:39:51.000000000 +0000 @@ -28,10 +28,10 @@ struct grantpt_info info; int fd; - if((fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0)) < 0){ - printk("get_pty : Couldn't open /dev/ptmx - errno = %d\n", - errno); - return(-1); + fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0); + if(fd < 0){ + printk("get_pty : Couldn't open /dev/ptmx - err = %d\n", -fd); + return(fd); } info.fd = fd; @@ -39,7 +39,7 @@ if(info.res < 0){ printk("get_pty : Couldn't grant pty - errno = %d\n", - info.err); + -info.err); return(-1); } if(unlockpt(fd) < 0){ --- diff/arch/um/sys-i386/Makefile 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/sys-i386/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -1,7 +1,8 @@ -obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o module.o \ - ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o +obj-y = bugs.o checksum.o fault.o ksyms.o ldt.o ptrace.o \ + ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o time.o obj-$(CONFIG_HIGHMEM) += highmem.o +obj-$(CONFIG_MODULES) += module.o USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) @@ -9,6 +10,8 @@ SYMLINKS = semaphore.c highmem.c module.c SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f) +clean-files := $(SYMLINKS) + semaphore.c-dir = kernel highmem.c-dir = mm module.c-dir = kernel @@ -24,8 +27,7 @@ $(SYMLINKS): $(call make_link,$@) -clean: - $(MAKE) -C util clean +subdir- := util fastdep: --- diff/arch/um/sys-i386/bugs.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/sys-i386/bugs.c 2004-02-09 10:39:51.000000000 +0000 @@ -4,20 +4,21 @@ */ #include -#include #include #include #include +#include #include "kern_util.h" #include "user.h" #include "sysdep/ptrace.h" #include "task.h" +#include "os.h" #define MAXTOKEN 64 /* Set during early boot */ -int cpu_has_cmov = 1; -int cpu_has_xmm = 0; +int host_has_cmov = 1; +int host_has_xmm = 0; static char token(int fd, char *buf, int len, char stop) { @@ -27,13 +28,15 @@ ptr = buf; end = &buf[len]; do { - n = read(fd, ptr, sizeof(*ptr)); + n = os_read_file(fd, ptr, sizeof(*ptr)); c = *ptr++; - if(n == 0) return(0); - else if(n != sizeof(*ptr)){ - printk("Reading /proc/cpuinfo failed, " - "errno = %d\n", errno); - return(-errno); + if(n != sizeof(*ptr)){ + if(n == 0) return(0); + printk("Reading /proc/cpuinfo failed, err = %d\n", -n); + if(n < 0) + return(n); + else + return(-EIO); } } while((c != '\n') && (c != stop) && (ptr < end)); @@ -45,45 +48,79 @@ return(c); } -static int check_cpu_feature(char *feature, int *have_it) +static int find_cpuinfo_line(int fd, char *key, char *scratch, int len) { - char buf[MAXTOKEN], c; - int fd, len = sizeof(buf)/sizeof(buf[0]), n; - - printk("Checking for host processor %s support...", feature); - fd = open("/proc/cpuinfo", O_RDONLY); - if(fd < 0){ - printk("Couldn't open /proc/cpuinfo, errno = %d\n", errno); - return(0); - } + int n; + char c; - *have_it = 0; - buf[len - 1] = '\0'; + scratch[len - 1] = '\0'; while(1){ - c = token(fd, buf, len - 1, ':'); - if(c <= 0) goto out; + c = token(fd, scratch, len - 1, ':'); + if(c <= 0) + return(0); else if(c != ':'){ printk("Failed to find ':' in /proc/cpuinfo\n"); - goto out; + return(0); } - if(!strncmp(buf, "flags", strlen("flags"))) break; + if(!strncmp(scratch, key, strlen(key))) + return(1); do { - n = read(fd, &c, sizeof(c)); + n = os_read_file(fd, &c, sizeof(c)); if(n != sizeof(c)){ printk("Failed to find newline in " - "/proc/cpuinfo, n = %d, errno = %d\n", - n, errno); - goto out; + "/proc/cpuinfo, err = %d\n", -n); + return(0); } } while(c != '\n'); } + return(0); +} + +int cpu_feature(char *what, char *buf, int len) +{ + int fd, ret = 0; + + fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd); + return(0); + } + + if(!find_cpuinfo_line(fd, what, buf, len)){ + printk("Couldn't find '%s' line in /proc/cpuinfo\n", what); + goto out_close; + } + + token(fd, buf, len, '\n'); + ret = 1; + + out_close: + os_close_file(fd); + return(ret); +} + +static int check_cpu_flag(char *feature, int *have_it) +{ + char buf[MAXTOKEN], c; + int fd, len = sizeof(buf)/sizeof(buf[0]); + + printk("Checking for host processor %s support...", feature); + fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd); + return(0); + } + + *have_it = 0; + if(!find_cpuinfo_line(fd, "flags", buf, sizeof(buf) / sizeof(buf[0]))) + goto out; c = token(fd, buf, len - 1, ' '); if(c < 0) goto out; else if(c != ' '){ - printk("Failed to find ':' in /proc/cpuinfo\n"); + printk("Failed to find ' ' in /proc/cpuinfo\n"); goto out; } @@ -100,21 +137,48 @@ out: if(*have_it == 0) printk("No\n"); else if(*have_it == 1) printk("Yes\n"); - close(fd); + os_close_file(fd); return(1); } +#if 0 /* This doesn't work in tt mode, plus it's causing compilation problems + * for some people. + */ +static void disable_lcall(void) +{ + struct modify_ldt_ldt_s ldt; + int err; + + bzero(&ldt, sizeof(ldt)); + ldt.entry_number = 7; + ldt.base_addr = 0; + ldt.limit = 0; + err = modify_ldt(1, &ldt, sizeof(ldt)); + if(err) + printk("Failed to disable lcall7 - errno = %d\n", errno); +} +#endif + +void arch_init_thread(void) +{ +#if 0 + disable_lcall(); +#endif +} + void arch_check_bugs(void) { int have_it; - if(access("/proc/cpuinfo", R_OK)){ + if(os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0){ printk("/proc/cpuinfo not available - skipping CPU capability " "checks\n"); return; } - if(check_cpu_feature("cmov", &have_it)) cpu_has_cmov = have_it; - if(check_cpu_feature("xmm", &have_it)) cpu_has_xmm = have_it; + if(check_cpu_flag("cmov", &have_it)) + host_has_cmov = have_it; + if(check_cpu_flag("xmm", &have_it)) + host_has_xmm = have_it; } int arch_handle_signal(int sig, union uml_pt_regs *regs) @@ -130,18 +194,18 @@ if((*((char *) ip) != 0x0f) || ((*((char *) (ip + 1)) & 0xf0) != 0x40)) return(0); - if(cpu_has_cmov == 0) + if(host_has_cmov == 0) panic("SIGILL caused by cmov, which this processor doesn't " "implement, boot a filesystem compiled for older " "processors"); - else if(cpu_has_cmov == 1) + else if(host_has_cmov == 1) panic("SIGILL caused by cmov, which this processor claims to " "implement"); - else if(cpu_has_cmov == -1) + else if(host_has_cmov == -1) panic("SIGILL caused by cmov, couldn't tell if this processor " "implements it, boot a filesystem compiled for older " "processors"); - else panic("Bad value for cpu_has_cmov (%d)", cpu_has_cmov); + else panic("Bad value for host_has_cmov (%d)", host_has_cmov); return(0); } --- diff/arch/um/sys-i386/ptrace_user.c 2003-01-02 10:43:05.000000000 +0000 +++ source/arch/um/sys-i386/ptrace_user.c 2004-02-09 10:39:51.000000000 +0000 @@ -39,10 +39,10 @@ nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]); for(i = 0; i < nregs; i++){ if((i == 4) || (i == 5)) continue; - if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i], + if(ptrace(PTRACE_POKEUSER, pid, &dummy->u_debugreg[i], regs[i]) < 0) - printk("write_debugregs - ptrace failed, " - "errno = %d\n", errno); + printk("write_debugregs - ptrace failed on " + "register %d, errno = %d\n", errno); } } @@ -54,7 +54,7 @@ dummy = NULL; nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]); for(i = 0; i < nregs; i++){ - regs[i] = ptrace(PTRACE_PEEKUSR, pid, + regs[i] = ptrace(PTRACE_PEEKUSER, pid, &dummy->u_debugreg[i], 0); } } --- diff/arch/um/sys-i386/util/Makefile 2003-05-21 11:49:50.000000000 +0100 +++ source/arch/um/sys-i386/util/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -6,10 +6,10 @@ mk_sc-objs := mk_sc.o $(obj)/mk_thread : $(obj)/mk_thread_kern.o $(obj)/mk_thread_user.o - $(CC) $(CFLAGS) -o $@ $^ + $(HOSTCC) $(CFLAGS) -o $@ $^ $(obj)/mk_thread_user.o : $(src)/mk_thread_user.c - $(CC) $(USER_CFLAGS) -c -o $@ $< + $(HOSTCC) $(USER_CFLAGS) -c -o $@ $< clean : $(RM) -f $(build-targets) --- diff/arch/um/sys-i386/util/mk_sc.c 2002-10-16 04:28:35.000000000 +0100 +++ source/arch/um/sys-i386/util/mk_sc.c 2004-02-09 10:39:51.000000000 +0000 @@ -38,6 +38,7 @@ SC_OFFSET("SC_ERR", err); SC_OFFSET("SC_CR2", cr2); SC_OFFSET("SC_FPSTATE", fpstate); + SC_OFFSET("SC_SIGMASK", oldmask); SC_FP_OFFSET("SC_FP_CW", cw); SC_FP_OFFSET("SC_FP_SW", sw); SC_FP_OFFSET("SC_FP_TAG", tag); --- diff/arch/um/uml.lds.S 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/uml.lds.S 2004-02-09 10:39:51.000000000 +0000 @@ -9,7 +9,6 @@ { . = START + SIZEOF_HEADERS; - . = ALIGN(4096); __binary_start = .; #ifdef MODE_TT .thread_private : { @@ -26,7 +25,11 @@ . = ALIGN(4096); /* Init code and data */ _stext = .; __init_begin = .; - .text.init : { *(.text.init) } + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } . = ALIGN(4096); .text : { @@ -38,7 +41,7 @@ #include "asm/common.lds.S" - .data.init : { *(.data.init) } + init.data : { *(init.data) } .data : { . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ --- diff/arch/um/util/Makefile 2003-05-21 11:49:50.000000000 +0100 +++ source/arch/um/util/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -3,19 +3,19 @@ mk_constants_user.o mk_constants_kern.o $(obj)/mk_task: $(obj)/mk_task_user.o $(obj)/mk_task_kern.o - $(CC) -o $@ $^ + $(HOSTCC) -o $@ $^ $(obj)/mk_task_user.o: $(src)/mk_task_user.c - $(CC) -o $@ -c $< + $(HOSTCC) -o $@ -c $< $(obj)/mk_constants : $(obj)/mk_constants_user.o $(obj)/mk_constants_kern.o - $(CC) -o $@ $^ + $(HOSTCC) -o $@ $^ $(obj)/mk_constants_user.o : $(src)/mk_constants_user.c - $(CC) -c $< -o $@ + $(HOSTCC) -c $< -o $@ $(obj)/mk_constants_kern.o : $(src)/mk_constants_kern.c - $(CC) $(CFLAGS) -c $< -o $@ + $(HOSTCC) $(CFLAGS) -c $< -o $@ clean: $(RM) $(build-targets) --- diff/arch/um/util/mk_constants_kern.c 2003-10-09 09:47:16.000000000 +0100 +++ source/arch/um/util/mk_constants_kern.c 2004-02-09 10:39:51.000000000 +0000 @@ -1,5 +1,6 @@ #include "linux/kernel.h" #include "linux/stringify.h" +#include "linux/time.h" #include "asm/page.h" extern void print_head(void); @@ -11,6 +12,7 @@ { print_head(); print_constant_int("UM_KERN_PAGE_SIZE", PAGE_SIZE); + print_constant_str("UM_KERN_EMERG", KERN_EMERG); print_constant_str("UM_KERN_ALERT", KERN_ALERT); print_constant_str("UM_KERN_CRIT", KERN_CRIT); @@ -19,6 +21,8 @@ print_constant_str("UM_KERN_NOTICE", KERN_NOTICE); print_constant_str("UM_KERN_INFO", KERN_INFO); print_constant_str("UM_KERN_DEBUG", KERN_DEBUG); + + print_constant_int("UM_NSEC_PER_SEC", NSEC_PER_SEC); print_tail(); return(0); } --- diff/arch/x86_64/Kconfig 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/x86_64/Kconfig 2004-02-09 10:39:51.000000000 +0000 @@ -111,10 +111,6 @@ bool default y -config X86_GOOD_APIC - bool - default y - config X86_MSR tristate "/dev/cpu/*/msr - Model-specific register support" help @@ -433,6 +429,7 @@ config DEBUG_INFO bool "Compile the kernel with debug info" depends on DEBUG_KERNEL + default n help If you say Y here the resulting kernel image will include debugging info resulting in a larger kernel image. @@ -464,9 +461,8 @@ help Add a simple leak tracer to the IOMMU code. This is useful when you are debugging a buggy device driver that leaks IOMMU mappings. - -#config X86_REMOTE_DEBUG -# bool "kgdb debugging stub" + +source "arch/x86_64/Kconfig.kgdb" endmenu --- diff/arch/x86_64/Makefile 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/x86_64/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -52,7 +52,10 @@ ifneq ($(CONFIG_DEBUG_INFO),y) CFLAGS += -fno-asynchronous-unwind-tables endif -#CFLAGS += $(call check_gcc,-funit-at-a-time,) + +# Enable unit-at-a-time mode when possible. It shrinks the +# kernel considerably. +CFLAGS += $(call check_gcc,-funit-at-a-time,) head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o --- diff/arch/x86_64/ia32/sys_ia32.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/x86_64/ia32/sys_ia32.c 2004-02-09 10:39:51.000000000 +0000 @@ -274,13 +274,16 @@ return -EINVAL; if (act) { + compat_uptr_t handler, restorer; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || - __get_user((long)new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(handler, &act->sa_handler) || __get_user(new_ka.sa.sa_flags, &act->sa_flags) || - __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer)|| + __get_user(restorer, &act->sa_restorer)|| __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t))) return -EFAULT; - + new_ka.sa.sa_handler = compat_ptr(handler); + new_ka.sa.sa_restorer = compat_ptr(restorer); /* FIXME: here we rely on _COMPAT_NSIG_WORS to be >= than _NSIG_WORDS << 1 */ switch (_NSIG_WORDS) { case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] @@ -331,13 +334,18 @@ if (act) { compat_old_sigset_t mask; + compat_uptr_t handler, restorer; if (verify_area(VERIFY_READ, act, sizeof(*act)) || - __get_user((long)new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(handler, &act->sa_handler) || __get_user(new_ka.sa.sa_flags, &act->sa_flags) || - __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer) || + __get_user(restorer, &act->sa_restorer) || __get_user(mask, &act->sa_mask)) return -EFAULT; + + new_ka.sa.sa_handler = compat_ptr(handler); + new_ka.sa.sa_restorer = compat_ptr(restorer); + siginitset(&new_ka.sa.sa_mask, mask); } @@ -525,7 +533,7 @@ put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); - ((char *) dirent) += reclen; + dirent = ((void *)dirent) + reclen; buf->current_dir = dirent; buf->count -= reclen; return 0; --- diff/arch/x86_64/kernel/Makefile 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/x86_64/kernel/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -24,6 +24,7 @@ obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o pci-dma.o obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_KGDB) += kgdb_stub.o obj-y += topology.o --- diff/arch/x86_64/kernel/acpi/boot.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/x86_64/kernel/acpi/boot.c 2004-02-09 10:39:51.000000000 +0000 @@ -51,8 +51,8 @@ int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ int acpi_ht __initdata = 1; /* enable HT */ -int acpi_lapic = 0; -int acpi_ioapic = 0; +int acpi_lapic; +int acpi_ioapic; /* -------------------------------------------------------------------------- Boot-time Configuration @@ -439,7 +439,7 @@ * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). */ - result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr); + result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); return result; @@ -447,7 +447,8 @@ mp_register_lapic_address(acpi_lapic_addr); - result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic); + result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic, + MAX_APICS); if (!result) { printk(KERN_ERR PREFIX "No LAPIC entries present\n"); /* TBD: Cleanup to allow fallback to MPS */ @@ -459,7 +460,7 @@ return result; } - result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi); + result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); /* TBD: Cleanup to allow fallback to MPS */ @@ -496,8 +497,8 @@ return 1; } - result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic); - if (!result) { + result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic, MAX_IO_APICS); + if (!result) { printk(KERN_ERR PREFIX "No IOAPIC entries present\n"); return -ENODEV; } @@ -509,14 +510,15 @@ /* Build a default routing table for legacy (ISA) interrupts. */ mp_config_acpi_legacy_irqs(); - result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr); + result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, NR_IRQ_VECTORS); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); /* TBD: Cleanup to allow fallback to MPS */ return result; } - result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src); + result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, + NR_IRQ_VECTORS); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); /* TBD: Cleanup to allow fallback to MPS */ --- diff/arch/x86_64/kernel/aperture.c 2003-08-26 10:00:52.000000000 +0100 +++ source/arch/x86_64/kernel/aperture.c 2004-02-09 10:39:51.000000000 +0000 @@ -87,13 +87,15 @@ /* Find a PCI capability */ static __u32 __init find_cap(int num, int slot, int func, int cap) { + u8 pos; + int bytes; if (!(read_pci_config_16(num,slot,func,PCI_STATUS) & PCI_STATUS_CAP_LIST)) return 0; - u8 pos = read_pci_config_byte(num,slot,func,PCI_CAPABILITY_LIST); - int bytes; + pos = read_pci_config_byte(num,slot,func,PCI_CAPABILITY_LIST); for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) { + u8 id; pos &= ~3; - u8 id = read_pci_config_byte(num,slot,func,pos+PCI_CAP_LIST_ID); + id = read_pci_config_byte(num,slot,func,pos+PCI_CAP_LIST_ID); if (id == 0xff) break; if (id == cap) @@ -106,26 +108,31 @@ /* Read a standard AGPv3 bridge header */ static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order) { - printk("AGP bridge at %02x:%02x:%02x\n", num, slot, func); - u32 apsizereg = read_pci_config_16(num,slot,func, cap + 0x14); + u32 apsize; + u32 apsizereg; + int nbits; + u32 aper_low, aper_hi; + u64 aper; + printk("AGP bridge at %02x:%02x:%02x\n", num, slot, func); + apsizereg = read_pci_config_16(num,slot,func, cap + 0x14); if (apsizereg == 0xffffffff) { printk("APSIZE in AGP bridge unreadable\n"); return 0; } - u32 apsize = apsizereg & 0xfff; + apsize = apsizereg & 0xfff; /* Some BIOS use weird encodings not in the AGPv3 table. */ if (apsize & 0xff) apsize |= 0xf00; - int nbits = hweight16(apsize); + nbits = hweight16(apsize); *order = 7 - nbits; if ((int)*order < 0) /* < 32MB */ *order = 0; - u32 aper_low = read_pci_config(num,slot,func, 0x10); - u32 aper_hi = read_pci_config(num,slot,func,0x14); - u64 aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32); + aper_low = read_pci_config(num,slot,func, 0x10); + aper_hi = read_pci_config(num,slot,func,0x14); + aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32); printk("Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n", aper, 32 << *order, apsizereg); @@ -155,6 +162,7 @@ for (slot = 0; slot < 32; slot++) { for (func = 0; func < 8; func++) { u32 class, cap; + u8 type; class = read_pci_config(num,slot,func, PCI_CLASS_REVISION); if (class == 0xffffffff) @@ -172,7 +180,7 @@ } /* No multi-function device? */ - u8 type = read_pci_config_byte(num,slot,func, + type = read_pci_config_byte(num,slot,func, PCI_HEADER_TYPE); if (!(type & 0x80)) break; --- diff/arch/x86_64/kernel/early_printk.c 2003-06-09 14:18:18.000000000 +0100 +++ source/arch/x86_64/kernel/early_printk.c 2004-02-09 10:39:51.000000000 +0000 @@ -155,7 +155,7 @@ int n; va_list ap; va_start(ap,fmt); - n = vsnprintf(buf,512,fmt,ap); + n = vscnprintf(buf,512,fmt,ap); early_console->write(early_console,buf,n); va_end(ap); } --- diff/arch/x86_64/kernel/entry.S 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/x86_64/kernel/entry.S 2004-02-09 10:39:51.000000000 +0000 @@ -436,7 +436,7 @@ popq %rdi cli subl $1,%gs:pda_irqcount -#ifdef CONFIG_KGDB +#ifdef CONFIG_DEBUG_INFO movq RBP(%rdi),%rbp #endif leaq ARGOFFSET(%rdi),%rsp --- diff/arch/x86_64/kernel/irq.c 2004-01-19 10:22:55.000000000 +0000 +++ source/arch/x86_64/kernel/irq.c 2004-02-09 10:39:51.000000000 +0000 @@ -405,6 +405,9 @@ spin_unlock(&desc->lock); irq_exit(); + + kgdb_process_breakpoint(); + return 1; } --- diff/arch/x86_64/kernel/nmi.c 2003-09-30 15:46:12.000000000 +0100 +++ source/arch/x86_64/kernel/nmi.c 2004-02-09 10:39:51.000000000 +0000 @@ -311,11 +311,11 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) { + int sum, cpu = safe_smp_processor_id(); + if (nmi_watchdog_disabled) return; - int sum, cpu = safe_smp_processor_id(); - sum = read_pda(apic_timer_irqs); if (last_irq_sums[cpu] == sum) { /* --- diff/arch/x86_64/kernel/pci-gart.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/x86_64/kernel/pci-gart.c 2004-02-09 10:39:51.000000000 +0000 @@ -117,11 +117,11 @@ static void free_iommu(unsigned long offset, int size) { + unsigned long flags; if (size == 1) { clear_bit(offset, iommu_gart_bitmap); return; } - unsigned long flags; spin_lock_irqsave(&iommu_bitmap_lock, flags); __clear_bit_string(iommu_gart_bitmap, offset, size); spin_unlock_irqrestore(&iommu_bitmap_lock, flags); @@ -329,6 +329,7 @@ { unsigned long npages = to_pages(phys_mem, size); unsigned long iommu_page = alloc_iommu(npages); + int i; if (iommu_page == -1) { if (!nonforced_iommu(dev, phys_mem, size)) return phys_mem; @@ -338,7 +339,6 @@ return bad_dma_address; } - int i; for (i = 0; i < npages; i++) { iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem); SET_LEAK(iommu_page + i); @@ -398,11 +398,11 @@ struct scatterlist *sout, unsigned long pages) { unsigned long iommu_start = alloc_iommu(pages); - if (iommu_start == -1) - return -1; - unsigned long iommu_page = iommu_start; int i; + + if (iommu_start == -1) + return -1; for (i = start; i < stopat; i++) { struct scatterlist *s = &sg[i]; @@ -519,12 +519,12 @@ { unsigned long iommu_page; int npages; + int i; if (dma_addr < iommu_bus_base + EMERGENCY_PAGES*PAGE_SIZE || dma_addr > iommu_bus_base + iommu_size) return; iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT; npages = to_pages(dma_addr, size); - int i; for (i = 0; i < npages; i++) { iommu_gatt_base[iommu_page + i] = 0; CLEAR_LEAK(iommu_page + i); --- diff/arch/x86_64/kernel/smp.c 2003-11-25 15:24:57.000000000 +0000 +++ source/arch/x86_64/kernel/smp.c 2004-02-09 10:39:51.000000000 +0000 @@ -362,6 +362,18 @@ send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); } +#ifdef CONFIG_KGDB +/* + * By using the NMI code instead of a vector we just sneak thru the + * word generator coming out with just what we want. AND it does + * not matter if clustered_apic_mode is set or not. + */ +void smp_send_nmi_allbutself(void) +{ + send_IPI_allbutself(APIC_DM_NMI); +} +#endif + /* * Structure and data for smp_call_function(). This is designed to minimise * static memory requirements. It also looks cleaner. --- diff/arch/x86_64/kernel/suspend_asm.S 2002-12-30 10:17:12.000000000 +0000 +++ source/arch/x86_64/kernel/suspend_asm.S 2004-02-09 10:39:51.000000000 +0000 @@ -122,4 +122,4 @@ .quad 0 loop2: .quad 0 - .previous \ No newline at end of file + .previous --- diff/arch/x86_64/kernel/sys_x86_64.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/x86_64/kernel/sys_x86_64.c 2004-02-09 10:39:51.000000000 +0000 @@ -105,13 +105,13 @@ return -ENOMEM; if (addr) { - addr = PAGE_ALIGN(addr); + addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (end - len >= addr && (!vma || addr + len <= vma->vm_start)) return addr; - } - addr = mm->free_area_cache; + } else + addr = mm->free_area_cache; if (addr < begin) addr = begin; start_addr = addr; --- diff/arch/x86_64/kernel/traps.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/x86_64/kernel/traps.c 2004-02-09 10:39:51.000000000 +0000 @@ -45,6 +45,9 @@ #include #include +#ifdef CONFIG_KGDB +#include +#endif extern struct gate_struct idt_table[256]; --- diff/arch/x86_64/lib/Makefile 2003-06-30 10:07:20.000000000 +0100 +++ source/arch/x86_64/lib/Makefile 2004-02-09 10:39:51.000000000 +0000 @@ -11,3 +11,4 @@ lib-$(CONFIG_IO_DEBUG) += iodebug.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o +lib-$(CONFIG_KGDB) += kgdb_serial.o --- diff/arch/x86_64/lib/csum-partial.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/x86_64/lib/csum-partial.c 2004-02-09 10:39:51.000000000 +0000 @@ -56,6 +56,8 @@ } count >>= 1; /* nr of 32-bit words.. */ if (count) { + unsigned long zero; + unsigned count64; if (4 & (unsigned long) buff) { result += *(unsigned int *) buff; count--; @@ -65,8 +67,8 @@ count >>= 1; /* nr of 64-bit words.. */ /* main loop using 64byte blocks */ - unsigned long zero = 0; - unsigned count64 = count >> 3; + zero = 0; + count64 = count >> 3; while (count64) { asm("addq 0*8(%[src]),%[res]\n\t" "adcq 1*8(%[src]),%[res]\n\t" --- diff/arch/x86_64/mm/fault.c 2004-02-09 10:36:09.000000000 +0000 +++ source/arch/x86_64/mm/fault.c 2004-02-09 10:39:51.000000000 +0000 @@ -142,6 +142,10 @@ void dump_pagetable(unsigned long address) { pml4_t *pml4; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + asm("movq %%cr3,%0" : "=r" (pml4)); pml4 = __va((unsigned long)pml4 & PHYSICAL_PAGE_MASK); @@ -150,17 +154,17 @@ if (bad_address(pml4)) goto bad; if (!pml4_present(*pml4)) goto ret; - pgd_t *pgd = __pgd_offset_k((pgd_t *)pml4_page(*pml4), address); + pgd = __pgd_offset_k((pgd_t *)pml4_page(*pml4), address); if (bad_address(pgd)) goto bad; printk("PGD %lx ", pgd_val(*pgd)); if (!pgd_present(*pgd)) goto ret; - pmd_t *pmd = pmd_offset(pgd, address); + pmd = pmd_offset(pgd, address); if (bad_address(pmd)) goto bad; printk("PMD %lx ", pmd_val(*pmd)); if (!pmd_present(*pmd)) goto ret; - pte_t *pte = pte_offset_kernel(pmd, address); + pte = pte_offset_kernel(pmd, address); if (bad_address(pte)) goto bad; printk("PTE %lx", pte_val(*pte)); ret: --- diff/arch/x86_64/mm/init.c 2003-10-09 09:47:33.000000000 +0100 +++ source/arch/x86_64/mm/init.c 2004-02-09 10:39:51.000000000 +0000 @@ -39,7 +39,7 @@ #define Dprintk(x...) -extern char _stext; +extern char _stext[]; DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); @@ -80,7 +80,7 @@ /* References to section boundaries */ -extern char _text, _etext, _edata, __bss_start, _end; +extern char _text, _etext, _edata, __bss_start, _end[]; extern char __init_begin, __init_end; int after_bootmem; @@ -442,7 +442,7 @@ kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT); kclist_add(&kcore_vmalloc, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START); - kclist_add(&kcore_kernel, &_stext, &_end - &_stext); + kclist_add(&kcore_kernel, &_stext, _end - _stext); kclist_add(&kcore_modules, (void *)MODULES_VADDR, MODULES_LEN); kclist_add(&kcore_vsyscall, (void *)VSYSCALL_START, VSYSCALL_END - VSYSCALL_START); --- diff/drivers/Kconfig 2004-02-09 10:36:09.000000000 +0000 +++ source/drivers/Kconfig 2004-02-09 10:39:52.000000000 +0000 @@ -26,6 +26,8 @@ source "drivers/message/i2o/Kconfig" +source "drivers/macintosh/Kconfig" + source "net/Kconfig" source "drivers/isdn/Kconfig" --- diff/drivers/acpi/Kconfig 2004-01-19 10:22:55.000000000 +0000 +++ source/drivers/acpi/Kconfig 2004-02-09 10:39:52.000000000 +0000 @@ -263,5 +263,23 @@ particular, many Toshiba laptops require this for correct operation of the AC module. +config X86_PM_TIMER + bool "Power Management Timer Support" + depends on X86 && ACPI + depends on ACPI_BOOT && EXPERIMENTAL + default n + help + The Power Management Timer is available on all ACPI-capable, + in most cases even if ACPI is unusable or blacklisted. + + This timing source is not affected by powermanagement features + like aggressive processor idling, throttling, frequency and/or + voltage scaling, unlike the commonly used Time Stamp Counter + (TSC) timing source. + + So, if you see messages like 'Losing too many ticks!' in the + kernel logs, and/or you are using a this on a notebook which + does not yet have an HPET, you should say "Y" here. + endmenu --- diff/drivers/acpi/ac.c 2004-02-09 10:36:09.000000000 +0000 +++ source/drivers/acpi/ac.c 2004-02-09 10:39:52.000000000 +0000 @@ -246,8 +246,8 @@ memset(ac, 0, sizeof(struct acpi_ac)); ac->handle = device->handle; - sprintf(acpi_device_name(device), "%s", ACPI_AC_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_AC_CLASS); + strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_AC_CLASS); acpi_driver_data(device) = ac; result = acpi_ac_get_state(ac); --- diff/drivers/acpi/asus_acpi.c 2004-02-09 10:36:09.000000000 +0000 +++ source/drivers/acpi/asus_acpi.c 2004-02-09 10:39:52.000000000 +0000 @@ -869,8 +869,8 @@ memset(hotk, 0, sizeof(struct asus_hotk)); hotk->handle = device->handle; - sprintf(acpi_device_name(device), "%s", ACPI_HOTK_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_HOTK_CLASS); + strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_HOTK_CLASS); acpi_driver_data(device) = hotk; hotk->device = device; --- diff/drivers/acpi/battery.c 2004-02-09 10:36:09.000000000 +0000 +++ source/drivers/acpi/battery.c 2004-02-09 10:39:52.000000000 +0000 @@ -735,8 +735,8 @@ memset(battery, 0, sizeof(struct acpi_battery)); battery->handle = device->handle; - sprintf(acpi_device_name(device), "%s", ACPI_BATTERY_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_BATTERY_CLASS); + strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); acpi_driver_data(device) = battery; result = acpi_battery_check(battery); --- diff/drivers/acpi/bus.c 2004-02-09 10:36:09.000000000 +0000 +++ source/drivers/acpi/bus.c 2004-02-09 10:39:52.000000000 +0000 @@ -296,8 +296,8 @@ if (!event) return_VALUE(-ENOMEM); - sprintf(event->device_class, "%s", device->pnp.device_class); - sprintf(event->bus_id, "%s", device->pnp.bus_id); + strcpy(event->device_class, device->pnp.device_class); + strcpy(event->bus_id, device->pnp.bus_id); event->type = type; event->data = data; --- diff/drivers/acpi/button.c 2004-02-09 10:36:09.000000000 +0000 +++ source/drivers/acpi/button.c 2004-02-09 10:39:52.000000000 +0000 @@ -316,35 +316,35 @@ */ if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWER)) { button->type = ACPI_BUTTON_TYPE_POWER; - sprintf(acpi_device_name(device), "%s", + strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_POWER); sprintf(acpi_device_class(device), "%s/%s", ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER); } else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) { button->type = ACPI_BUTTON_TYPE_POWERF; - sprintf(acpi_device_name(device), "%s", + strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_POWERF); sprintf(acpi_device_class(device), "%s/%s", ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER); } else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEP)) { button->type = ACPI_BUTTON_TYPE_SLEEP; - sprintf(acpi_device_name(device), "%s", + strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_SLEEP); sprintf(acpi_device_class(device), "%s/%s", ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP); } else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) { button->type = ACPI_BUTTON_TYPE_SLEEPF; - sprintf(acpi_device_name(device), "%s", + strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_SLEEPF); sprintf(acpi_device_class(device), "%s/%s", ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP); } else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_LID)) { button->type = ACPI_BUTTON_TYPE_LID; - sprintf(acpi_device_name(device), "%s", + strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_LID); sprintf(acpi_device_class(device), "%s/%s", ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID); --- diff/drivers/acpi/ec.c 2004-02-09 10:36:09.000000000 +0000 +++ source/drivers/acpi/ec.c 2004-02-09 10:39:52.000000000 +0000 @@ -578,8 +578,8 @@ ec->handle = device->handle; ec->uid = -1; ec->lock = SPIN_LOCK_UNLOCKED; - sprintf(acpi_device_name(device), "%s", ACPI_EC_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_EC_CLASS); + strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_EC_CLASS); acpi_driver_data(device) = ec; /* Use the global lock for all EC transactions? */ --- diff/drivers/acpi/fan.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/acpi/fan.c 2004-02-09 10:39:52.000000000 +0000 @@ -214,8 +214,8 @@ memset(fan, 0, sizeof(struct acpi_fan)); fan->handle = device->handle; - sprintf(acpi_device_name(device), "%s", ACPI_FAN_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_FAN_CLASS); + strcpy(acpi_device_name(device), ACPI_FAN_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_FAN_CLASS); acpi_driver_data(device) = fan; result = acpi_bus_get_power(fan->handle, &state); --- diff/drivers/acpi/numa.c 2003-02-26 16:01:07.000000000 +0000 +++ source/drivers/acpi/numa.c 2004-02-09 10:39:52.000000000 +0000 @@ -30,8 +30,9 @@ #include #include #include +#include -extern int __init acpi_table_parse_madt_family (enum acpi_table_id id, unsigned long madt_size, int entry_id, acpi_madt_entry_handler handler); +extern int __init acpi_table_parse_madt_family (enum acpi_table_id id, unsigned long madt_size, int entry_id, acpi_madt_entry_handler handler, unsigned int max_entries); void __init acpi_table_print_srat_entry ( @@ -46,9 +47,9 @@ { struct acpi_table_processor_affinity *p = (struct acpi_table_processor_affinity*) header; - printk(KERN_INFO PREFIX "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n", p->apic_id, p->lsapic_eid, p->proximity_domain, - p->flags.enabled?"enabled":"disabled"); + p->flags.enabled?"enabled":"disabled")); } break; @@ -56,11 +57,11 @@ { struct acpi_table_memory_affinity *p = (struct acpi_table_memory_affinity*) header; - printk(KERN_INFO PREFIX "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n", p->base_addr_hi, p->base_addr_lo, p->length_hi, p->length_lo, p->memory_type, p->proximity_domain, p->flags.enabled ? "enabled" : "disabled", - p->flags.hot_pluggable ? " hot-pluggable" : ""); + p->flags.hot_pluggable ? " hot-pluggable" : "")); } break; @@ -97,7 +98,7 @@ static int __init acpi_parse_processor_affinity (acpi_table_entry_header *header) { - struct acpi_table_processor_affinity *processor_affinity = NULL; + struct acpi_table_processor_affinity *processor_affinity; processor_affinity = (struct acpi_table_processor_affinity*) header; if (!processor_affinity) @@ -115,7 +116,7 @@ static int __init acpi_parse_memory_affinity (acpi_table_entry_header *header) { - struct acpi_table_memory_affinity *memory_affinity = NULL; + struct acpi_table_memory_affinity *memory_affinity; memory_affinity = (struct acpi_table_memory_affinity*) header; if (!memory_affinity) @@ -133,7 +134,7 @@ static int __init acpi_parse_srat (unsigned long phys_addr, unsigned long size) { - struct acpi_table_srat *srat = NULL; + struct acpi_table_srat *srat; if (!phys_addr || !size) return -EINVAL; @@ -149,10 +150,11 @@ int __init acpi_table_parse_srat ( enum acpi_srat_entry_id id, - acpi_madt_entry_handler handler) + acpi_madt_entry_handler handler, + unsigned int max_entries) { return acpi_table_parse_madt_family(ACPI_SRAT, sizeof(struct acpi_table_srat), - id, handler); + id, handler, max_entries); } @@ -166,9 +168,11 @@ if (result > 0) { result = acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY, - acpi_parse_processor_affinity); + acpi_parse_processor_affinity, + NR_CPUS); result = acpi_table_parse_srat(ACPI_SRAT_MEMORY_AFFINITY, - acpi_parse_memory_affinity); + acpi_parse_memory_affinity, + NR_MEMBLKS); } else { /* FIXME */ printk("Warning: acpi_table_parse(ACPI_SRAT) returned %d!\n",result); --- diff/drivers/acpi/osl.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/acpi/osl.c 2004-02-09 10:39:52.000000000 +0000 @@ -249,7 +249,7 @@ */ irq = acpi_fadt.sci_int; -#ifdef CONFIG_IA64 +#if defined(CONFIG_IA64) || defined(CONFIG_PCI_USE_VECTOR) irq = acpi_irq_to_vector(irq); if (irq < 0) { printk(KERN_ERR PREFIX "SCI (ACPI interrupt %d) not registered\n", @@ -272,7 +272,7 @@ acpi_os_remove_interrupt_handler(u32 irq, OSD_HANDLER handler) { if (irq) { -#ifdef CONFIG_IA64 +#if defined(CONFIG_IA64) || defined(CONFIG_PCI_USE_VECTOR) irq = acpi_irq_to_vector(irq); #endif free_irq(irq, acpi_irq); --- diff/drivers/acpi/pci_link.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/acpi/pci_link.c 2004-02-09 10:39:52.000000000 +0000 @@ -652,8 +652,8 @@ link->device = device; link->handle = device->handle; - sprintf(acpi_device_name(device), "%s", ACPI_PCI_LINK_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_PCI_LINK_CLASS); + strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS); acpi_driver_data(device) = link; result = acpi_pci_link_get_possible(link); --- diff/drivers/acpi/pci_root.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/acpi/pci_root.c 2004-02-09 10:39:52.000000000 +0000 @@ -134,8 +134,8 @@ memset(root, 0, sizeof(struct acpi_pci_root)); root->handle = device->handle; - sprintf(acpi_device_name(device), "%s", ACPI_PCI_ROOT_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_PCI_ROOT_CLASS); + strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); acpi_driver_data(device) = root; /* --- diff/drivers/acpi/power.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/acpi/power.c 2004-02-09 10:39:52.000000000 +0000 @@ -503,9 +503,9 @@ memset(resource, 0, sizeof(struct acpi_power_resource)); resource->handle = device->handle; - sprintf(resource->name, "%s", device->pnp.bus_id); - sprintf(acpi_device_name(device), "%s", ACPI_POWER_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_POWER_CLASS); + strcpy(resource->name, device->pnp.bus_id); + strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_POWER_CLASS); acpi_driver_data(device) = resource; /* Evalute the object to get the system level and resource order. */ --- diff/drivers/acpi/processor.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/acpi/processor.c 2004-02-09 10:39:52.000000000 +0000 @@ -3,6 +3,7 @@ * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh + * Copyright (C) 2004 Dominik Brodowski * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -22,7 +23,7 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * TBD: - * 1. Make # power/performance states dynamic. + * 1. Make # power states dynamic. * 2. Support duty_cycle values that span bit 4. * 3. Optimize by having scheduler determine business instead of * having us try to calculate it here. @@ -55,9 +56,9 @@ #define ACPI_PROCESSOR_DEVICE_NAME "Processor" #define ACPI_PROCESSOR_FILE_INFO "info" #define ACPI_PROCESSOR_FILE_POWER "power" -#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" #define ACPI_PROCESSOR_FILE_THROTTLING "throttling" #define ACPI_PROCESSOR_FILE_LIMIT "limit" +#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 #define ACPI_PROCESSOR_NOTIFY_POWER 0x81 @@ -746,7 +747,62 @@ /* -------------------------------------------------------------------------- Performance Management -------------------------------------------------------------------------- */ -int +#ifdef CONFIG_CPU_FREQ + +static DECLARE_MUTEX(performance_sem); + +/* + * _PPC support is implemented as a CPUfreq policy notifier: + * This means each time a CPUfreq driver registered also with + * the ACPI core is asked to change the speed policy, the maximum + * value is adjusted so that it is within the platform limit. + * + * Also, when a new platform limit value is detected, the CPUfreq + * policy is adjusted accordingly. + */ + +static int acpi_processor_ppc_is_init = 0; + +static int acpi_processor_ppc_notifier(struct notifier_block *nb, + unsigned long event, + void *data) +{ + struct cpufreq_policy *policy = data; + struct acpi_processor *pr; + unsigned int ppc = 0; + + down(&performance_sem); + + if (event != CPUFREQ_INCOMPATIBLE) + goto out; + + pr = processors[policy->cpu]; + if (!pr || !pr->performance) + goto out; + + ppc = (unsigned int) pr->performance_platform_limit; + if (!ppc) + goto out; + + if (ppc > pr->performance->state_count) + goto out; + + cpufreq_verify_within_limits(policy, 0, + pr->performance->states[ppc].core_frequency * 1000); + + out: + up(&performance_sem); + + return 0; +} + + +static struct notifier_block acpi_ppc_notifier_block = { + .notifier_call = acpi_processor_ppc_notifier, +}; + + +static int acpi_processor_get_platform_limit ( struct acpi_processor* pr) { @@ -770,35 +826,491 @@ pr->performance_platform_limit = (int) ppc; - acpi_processor_get_limit_info(pr); + return_VALUE(0); +} + + +static int acpi_processor_ppc_has_changed( + struct acpi_processor *pr) +{ + int ret = acpi_processor_get_platform_limit(pr); + if (ret < 0) + return (ret); + else + return cpufreq_update_policy(pr->id); +} + + +static void acpi_processor_ppc_init(void) { + if (!cpufreq_register_notifier(&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER)) + acpi_processor_ppc_is_init = 1; + else + printk(KERN_DEBUG "Warning: Processor Platform Limit not supported.\n"); +} + + +static void acpi_processor_ppc_exit(void) { + if (acpi_processor_ppc_is_init) + cpufreq_unregister_notifier(&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER); + + acpi_processor_ppc_is_init = 0; +} + +/* + * when registering a cpufreq driver with this ACPI processor driver, the + * _PCT and _PSS structures are read out and written into struct + * acpi_processor_performance. + */ + +static int acpi_processor_set_pdc (struct acpi_processor *pr) +{ + acpi_status status = AE_OK; + u32 arg0_buf[3]; + union acpi_object arg0 = {ACPI_TYPE_BUFFER}; + struct acpi_object_list no_object = {1, &arg0}; + struct acpi_object_list *pdc; + + ACPI_FUNCTION_TRACE("acpi_processor_set_pdc"); + arg0.buffer.length = 12; + arg0.buffer.pointer = (u8 *) arg0_buf; + arg0_buf[0] = ACPI_PDC_REVISION_ID; + arg0_buf[1] = 0; + arg0_buf[2] = 0; + + pdc = (pr->performance->pdc) ? pr->performance->pdc : &no_object; + + status = acpi_evaluate_object(pr->handle, "_PDC", pdc, NULL); + + if ((ACPI_FAILURE(status)) && (pr->performance->pdc)) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating _PDC, using legacy perf. control...\n")); + + return_VALUE(status); +} + + +static int +acpi_processor_get_performance_control ( + struct acpi_processor *pr) +{ + int result = 0; + acpi_status status = 0; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *pct = NULL; + union acpi_object obj = {0}; + + ACPI_FUNCTION_TRACE("acpi_processor_get_performance_control"); + + status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer); + if(ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PCT\n")); + return_VALUE(-ENODEV); + } + + pct = (union acpi_object *) buffer.pointer; + if (!pct || (pct->type != ACPI_TYPE_PACKAGE) + || (pct->package.count != 2)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PCT data\n")); + result = -EFAULT; + goto end; + } + + /* + * control_register + */ + + obj = pct->package.elements[0]; + + if ((obj.type != ACPI_TYPE_BUFFER) + || (obj.buffer.length < sizeof(struct acpi_pct_register)) + || (obj.buffer.pointer == NULL)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Invalid _PCT data (control_register)\n")); + result = -EFAULT; + goto end; + } + memcpy(&pr->performance->control_register, obj.buffer.pointer, sizeof(struct acpi_pct_register)); + + + /* + * status_register + */ + + obj = pct->package.elements[1]; + + if ((obj.type != ACPI_TYPE_BUFFER) + || (obj.buffer.length < sizeof(struct acpi_pct_register)) + || (obj.buffer.pointer == NULL)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Invalid _PCT data (status_register)\n")); + result = -EFAULT; + goto end; + } + + memcpy(&pr->performance->status_register, obj.buffer.pointer, sizeof(struct acpi_pct_register)); + +end: + acpi_os_free(buffer.pointer); + + return_VALUE(result); +} + + +static int +acpi_processor_get_performance_states ( + struct acpi_processor *pr) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + struct acpi_buffer format = {sizeof("NNNNNN"), "NNNNNN"}; + struct acpi_buffer state = {0, NULL}; + union acpi_object *pss = NULL; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_get_performance_states"); + + status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer); + if(ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PSS\n")); + return_VALUE(-ENODEV); + } + + pss = (union acpi_object *) buffer.pointer; + if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n")); + result = -EFAULT; + goto end; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states\n", + pss->package.count)); + + pr->performance->state_count = pss->package.count; + pr->performance->states = kmalloc(sizeof(struct acpi_processor_px) * pss->package.count, GFP_KERNEL); + if (!pr->performance->states) { + result = -ENOMEM; + goto end; + } + + for (i = 0; i < pr->performance->state_count; i++) { + + struct acpi_processor_px *px = &(pr->performance->states[i]); + + state.length = sizeof(struct acpi_processor_px); + state.pointer = px; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i)); + + status = acpi_extract_package(&(pss->package.elements[i]), + &format, &state); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n")); + result = -EFAULT; + kfree(pr->performance->states); + goto end; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]\n", + i, + (u32) px->core_frequency, + (u32) px->power, + (u32) px->transition_latency, + (u32) px->bus_master_latency, + (u32) px->control, + (u32) px->status)); + + if (!px->core_frequency) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "core_frequency is 0\n")); + result = -EFAULT; + kfree(pr->performance->states); + goto end; + } + } + +end: + acpi_os_free(buffer.pointer); + + return_VALUE(result); +} + + +static int +acpi_processor_get_performance_info ( + struct acpi_processor *pr) +{ + int result = 0; + acpi_status status = AE_OK; + acpi_handle handle = NULL; + + ACPI_FUNCTION_TRACE("acpi_processor_get_performance_info"); + + if (!pr || !pr->performance || !pr->handle) + return_VALUE(-EINVAL); + + status = acpi_get_handle(pr->handle, "_PCT", &handle); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "ACPI-based processor performance control unavailable\n")); + return_VALUE(-ENODEV); + } + + acpi_processor_set_pdc(pr); + + result = acpi_processor_get_performance_control(pr); + if (result) + return_VALUE(result); + + result = acpi_processor_get_performance_states(pr); + if (result) + return_VALUE(result); + + result = acpi_processor_get_platform_limit(pr); + if (result) + return_VALUE(result); + return_VALUE(0); } -EXPORT_SYMBOL(acpi_processor_get_platform_limit); + + +#ifdef CONFIG_X86_ACPI_CPUFREQ_PROC_INTF +/* /proc/acpi/processor/../performance interface (DEPRECATED) */ + +static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file); +static struct file_operations acpi_processor_perf_fops = { + .open = acpi_processor_perf_open_fs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int acpi_processor_perf_seq_show(struct seq_file *seq, void *offset) +{ + struct acpi_processor *pr = (struct acpi_processor *)seq->private; + int i = 0; + + ACPI_FUNCTION_TRACE("acpi_processor_perf_seq_show"); + + if (!pr) + goto end; + + if (!pr->performance) { + seq_puts(seq, "\n"); + goto end; + } + + seq_printf(seq, "state count: %d\n" + "active state: P%d\n", + pr->performance->state_count, + pr->performance->state); + + seq_puts(seq, "states:\n"); + for (i = 0; i < pr->performance->state_count; i++) + seq_printf(seq, " %cP%d: %d MHz, %d mW, %d uS\n", + (i == pr->performance->state?'*':' '), i, + (u32) pr->performance->states[i].core_frequency, + (u32) pr->performance->states[i].power, + (u32) pr->performance->states[i].transition_latency); + +end: + return 0; +} + +static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file) +{ + return single_open(file, acpi_processor_perf_seq_show, + PDE(inode)->data); +} + +static int +acpi_processor_write_performance ( + struct file *file, + const char __user *buffer, + size_t count, + loff_t *data) +{ + int result = 0; + struct seq_file *m = (struct seq_file *) file->private_data; + struct acpi_processor *pr = (struct acpi_processor *) m->private; + struct acpi_processor_performance *perf; + char state_string[12] = {'\0'}; + unsigned int new_state = 0; + struct cpufreq_policy policy; + + ACPI_FUNCTION_TRACE("acpi_processor_write_performance"); + + if (!pr || (count > sizeof(state_string) - 1)) + return_VALUE(-EINVAL); + + perf = pr->performance; + if (!perf) + return_VALUE(-EINVAL); + + if (copy_from_user(state_string, buffer, count)) + return_VALUE(-EFAULT); + + state_string[count] = '\0'; + new_state = simple_strtoul(state_string, NULL, 0); + + if (new_state >= perf->state_count) + return_VALUE(-EINVAL); + + cpufreq_get_policy(&policy, pr->id); + + policy.cpu = pr->id; + policy.min = perf->states[new_state].core_frequency * 1000; + policy.max = perf->states[new_state].core_frequency * 1000; + + result = cpufreq_set_policy(&policy); + if (result) + return_VALUE(result); + + return_VALUE(count); +} + +static void +acpi_cpufreq_add_file ( + struct acpi_processor *pr) +{ + struct proc_dir_entry *entry = NULL; + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_cpufreq_addfile"); + + if (acpi_bus_get_device(pr->handle, &device)) + return_VOID; + + /* add file 'performance' [R/W] */ + entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE, + S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); + if (!entry) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' fs entry\n", + ACPI_PROCESSOR_FILE_PERFORMANCE)); + else { + entry->proc_fops = &acpi_processor_perf_fops; + entry->proc_fops->write = acpi_processor_write_performance; + entry->data = acpi_driver_data(device); + } + return_VOID; +} + +static void +acpi_cpufreq_remove_file ( + struct acpi_processor *pr) +{ + struct acpi_device *device = NULL; + + ACPI_FUNCTION_TRACE("acpi_cpufreq_addfile"); + + if (acpi_bus_get_device(pr->handle, &device)) + return_VOID; + + /* remove file 'performance' */ + remove_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE, + acpi_device_dir(device)); + + return_VOID; +} + +#else +static void acpi_cpufreq_add_file (struct acpi_processor *pr) { return; } +static void acpi_cpufreq_remove_file (struct acpi_processor *pr) { return; } +#endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */ + int acpi_processor_register_performance ( struct acpi_processor_performance * performance, - struct acpi_processor ** pr, unsigned int cpu) { + struct acpi_processor *pr; + ACPI_FUNCTION_TRACE("acpi_processor_register_performance"); - *pr = processors[cpu]; - if (!*pr) + if (!acpi_processor_ppc_is_init) + return_VALUE(-EINVAL); + + down(&performance_sem); + + pr = processors[cpu]; + if (!pr) { + up(&performance_sem); return_VALUE(-ENODEV); + } - if ((*pr)->performance) + if (pr->performance) { + up(&performance_sem); return_VALUE(-EBUSY); + } - (*pr)->performance = performance; - performance->pr = *pr; - return 0; + pr->performance = performance; + + if (acpi_processor_get_performance_info(pr)) { + pr->performance = NULL; + up(&performance_sem); + return_VALUE(-EIO); + } + + acpi_cpufreq_add_file(pr); + + up(&performance_sem); + return_VALUE(0); } EXPORT_SYMBOL(acpi_processor_register_performance); -/* for the rest of it, check cpufreq/acpi.c */ +void +acpi_processor_unregister_performance ( + struct acpi_processor_performance * performance, + unsigned int cpu) +{ + struct acpi_processor *pr; + + ACPI_FUNCTION_TRACE("acpi_processor_unregister_performance"); + + if (!acpi_processor_ppc_is_init) + return_VOID; + + down(&performance_sem); + + pr = processors[cpu]; + if (!pr) { + up(&performance_sem); + return_VOID; + } + + kfree(pr->performance->states); + pr->performance = NULL; + + acpi_cpufreq_remove_file(pr); + + up(&performance_sem); + + return_VOID; +} +EXPORT_SYMBOL(acpi_processor_unregister_performance); + + +/* for the rest of it, check arch/i386/kernel/cpu/cpufreq/acpi.c */ + +#else /* !CONFIG_CPU_FREQ */ + +static void acpi_processor_ppc_init(void) { return; } +static void acpi_processor_ppc_exit(void) { return; } + +static int acpi_processor_ppc_has_changed(struct acpi_processor *pr) { + static unsigned int printout = 1; + if (printout) { + printk(KERN_WARNING "Warning: Processor Platform Limit event detected, but not handled.\n"); + printk(KERN_WARNING "Consider compiling CPUfreq support into your kernel.\n"); + printout = 0; + } + return 0; +} + +#endif /* CONFIG_CPU_FREQ */ /* -------------------------------------------------------------------------- Throttling Control @@ -1043,27 +1555,6 @@ if (!pr->flags.limit) return_VALUE(-ENODEV); -#ifdef CONFIG_CPU_FREQ - if (pr->flags.performance) { - px = pr->performance_platform_limit; - if (pr->limit.user.px > px) - px = pr->limit.user.px; - if (pr->limit.thermal.px > px) - px = pr->limit.thermal.px; - { - struct cpufreq_policy policy; - policy.cpu = pr->id; - cpufreq_get_policy(&policy, pr->id); - policy.max = pr->performance->states[px].core_frequency * 1000; /* racy */ - result = cpufreq_set_policy(&policy); - } - if (result) - goto end; - } else if (pr->performance_platform_limit) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Platform limit event detected. Consider using ACPI P-States CPUfreq driver\n")); - } -#endif - if (pr->flags.throttling) { if (pr->limit.user.tx > tx) tx = pr->limit.user.tx; @@ -1091,6 +1582,113 @@ } +#ifdef CONFIG_CPU_FREQ + +/* If a passive cooling situation is detected, primarily CPUfreq is used, as it + * offers (in most cases) voltage scaling in addition to frequency scaling, and + * thus a cubic (instead of linear) reduction of energy. Also, we allow for + * _any_ cpufreq driver and not only the acpi-cpufreq driver. + */ + +static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS]; +static unsigned int acpi_thermal_cpufreq_is_init = 0; + + +static int cpu_has_cpufreq(unsigned int cpu) +{ + struct cpufreq_policy policy; + if (!acpi_thermal_cpufreq_is_init) + return -ENODEV; + if (!cpufreq_get_policy(&policy, cpu)) + return -ENODEV; + return 0; +} + + +static int acpi_thermal_cpufreq_increase(unsigned int cpu) +{ + if (!cpu_has_cpufreq) + return -ENODEV; + + if (cpufreq_thermal_reduction_pctg[cpu] < 60) { + cpufreq_thermal_reduction_pctg[cpu] += 20; + cpufreq_update_policy(cpu); + return 0; + } + + return -ERANGE; +} + + +static int acpi_thermal_cpufreq_decrease(unsigned int cpu) +{ + if (!cpu_has_cpufreq) + return -ENODEV; + + if (cpufreq_thermal_reduction_pctg[cpu] >= 20) { + cpufreq_thermal_reduction_pctg[cpu] -= 20; + cpufreq_update_policy(cpu); + return 0; + } + + return -ERANGE; +} + + +static int acpi_thermal_cpufreq_notifier( + struct notifier_block *nb, + unsigned long event, + void *data) +{ + struct cpufreq_policy *policy = data; + unsigned long max_freq = 0; + + if (event != CPUFREQ_ADJUST) + goto out; + + max_freq = (policy->cpuinfo.max_freq * (100 - cpufreq_thermal_reduction_pctg[policy->cpu])) / 100; + + cpufreq_verify_within_limits(policy, 0, max_freq); + + out: + return 0; +} + + +static struct notifier_block acpi_thermal_cpufreq_notifier_block = { + .notifier_call = acpi_thermal_cpufreq_notifier, +}; + + +static void acpi_thermal_cpufreq_init(void) { + int i; + + for (i=0; iflags.limit) - return_VALUE(-ENODEV); - /* Thermal limits are always relative to the current Px/Tx state. */ - if (pr->flags.performance) - pr->limit.thermal.px = pr->performance->state; if (pr->flags.throttling) pr->limit.thermal.tx = pr->throttling.state; @@ -1130,26 +1722,27 @@ * performance state. */ - px = pr->limit.thermal.px; tx = pr->limit.thermal.tx; switch (type) { case ACPI_PROCESSOR_LIMIT_NONE: - px = 0; + do { + result = acpi_thermal_cpufreq_decrease(pr->id); + } while (!result); tx = 0; break; case ACPI_PROCESSOR_LIMIT_INCREMENT: - if (pr->flags.performance) { - if (px == (pr->performance->state_count - 1)) - ACPI_DEBUG_PRINT((ACPI_DB_INFO, + /* if going up: P-states first, T-states later */ + + result = acpi_thermal_cpufreq_increase(pr->id); + if (!result) + goto end; + else if (result == -ERANGE) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "At maximum performance state\n")); - else { - px++; - goto end; - } - } + if (pr->flags.throttling) { if (tx == (pr->throttling.state_count - 1)) ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -1160,37 +1753,41 @@ break; case ACPI_PROCESSOR_LIMIT_DECREMENT: - if (pr->flags.performance) { - if (px == pr->performance_platform_limit) - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "At minimum performance state\n")); - else { - px--; - goto end; - } - } + /* if going down: T-states first, P-states later */ + if (pr->flags.throttling) { if (tx == 0) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "At minimum throttling state\n")); - else + else { tx--; + goto end; + } } + + result = acpi_thermal_cpufreq_decrease(pr->id); + if (result == -ERANGE) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "At minimum performance state\n")); + break; } end: - pr->limit.thermal.px = px; - pr->limit.thermal.tx = tx; + if (pr->flags.throttling) { + pr->limit.thermal.px = 0; + pr->limit.thermal.tx = tx; - result = acpi_processor_apply_limit(pr); - if (result) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to set thermal limit\n")); + result = acpi_processor_apply_limit(pr); + if (result) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to set thermal limit\n")); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Thermal limit now (P%d:T%d)\n", - pr->limit.thermal.px, - pr->limit.thermal.tx)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Thermal limit now (P%d:T%d)\n", + pr->limit.thermal.px, + pr->limit.thermal.tx)); + } else + result = 0; return_VALUE(result); } @@ -1205,7 +1802,7 @@ if (!pr) return_VALUE(-EINVAL); - if (pr->flags.performance || pr->flags.throttling) + if (pr->flags.throttling) pr->flags.limit = 1; return_VALUE(0); @@ -1232,14 +1829,12 @@ "bus mastering control: %s\n" "power management: %s\n" "throttling control: %s\n" - "performance management: %s\n" "limit interface: %s\n", pr->id, pr->acpi_id, pr->flags.bm_control ? "yes" : "no", pr->flags.power ? "yes" : "no", pr->flags.throttling ? "yes" : "no", - pr->flags.performance ? "yes" : "no", pr->flags.limit ? "yes" : "no"); end: @@ -1396,11 +1991,9 @@ } seq_printf(seq, "active limit: P%d:T%d\n" - "platform limit: P%d:T0\n" "user limit: P%d:T%d\n" "thermal limit: P%d:T%d\n", pr->limit.state.px, pr->limit.state.tx, - pr->flags.performance?pr->performance_platform_limit:0, pr->limit.user.px, pr->limit.user.tx, pr->limit.thermal.px, pr->limit.thermal.tx); @@ -1447,15 +2040,6 @@ return_VALUE(-EINVAL); } - if (pr->flags.performance) { - if ((px < pr->performance_platform_limit) - || (px > (pr->performance->state_count - 1))) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid px\n")); - return_VALUE(-EINVAL); - } - pr->limit.user.px = px; - } - if (pr->flags.throttling) { if ((tx < 0) || (tx > (pr->throttling.state_count - 1))) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid tx\n")); @@ -1635,9 +2219,9 @@ } acpi_processor_get_power_info(pr); - pr->flags.performance = 0; - pr->performance_platform_limit = 0; - acpi_processor_get_platform_limit(pr); +#ifdef CONFIG_CPU_FREQ + acpi_processor_ppc_has_changed(pr); +#endif acpi_processor_get_throttling_info(pr); acpi_processor_get_limit_info(pr); @@ -1651,7 +2235,6 @@ u32 event, void *data) { - int result = 0; struct acpi_processor *pr = (struct acpi_processor *) data; struct acpi_device *device = NULL; @@ -1665,9 +2248,7 @@ switch (event) { case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: - result = acpi_processor_get_platform_limit(pr); - if (!result) - acpi_processor_apply_limit(pr); + acpi_processor_ppc_has_changed(pr); acpi_bus_generate_event(device, event, pr->performance_platform_limit); break; @@ -1705,8 +2286,8 @@ memset(pr, 0, sizeof(struct acpi_processor)); pr->handle = device->handle; - sprintf(acpi_device_name(device), "%s", ACPI_PROCESSOR_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_PROCESSOR_CLASS); + strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); acpi_driver_data(device) = pr; result = acpi_processor_get_info(pr); @@ -1813,6 +2394,10 @@ return_VALUE(-ENODEV); } + acpi_thermal_cpufreq_init(); + + acpi_processor_ppc_init(); + return_VALUE(0); } @@ -1822,6 +2407,10 @@ { ACPI_FUNCTION_TRACE("acpi_processor_exit"); + acpi_processor_ppc_exit(); + + acpi_thermal_cpufreq_exit(); + acpi_bus_unregister_driver(&acpi_processor_driver); remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); --- diff/drivers/acpi/scan.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/acpi/scan.c 2004-02-09 10:39:52.000000000 +0000 @@ -486,13 +486,13 @@ */ switch (type) { case ACPI_BUS_TYPE_SYSTEM: - sprintf(device->pnp.bus_id, "%s", "ACPI"); + strcpy(device->pnp.bus_id, "ACPI"); break; case ACPI_BUS_TYPE_POWER_BUTTON: - sprintf(device->pnp.bus_id, "%s", "PWRF"); + strcpy(device->pnp.bus_id, "PWRF"); break; case ACPI_BUS_TYPE_SLEEP_BUTTON: - sprintf(device->pnp.bus_id, "%s", "SLPF"); + strcpy(device->pnp.bus_id, "SLPF"); break; default: acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); @@ -503,7 +503,7 @@ else break; } - sprintf(device->pnp.bus_id, "%s", bus_id); + strcpy(device->pnp.bus_id, bus_id); break; } } @@ -565,16 +565,16 @@ */ if ((parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) { hid = ACPI_BUS_HID; - sprintf(device->pnp.device_name, "%s", ACPI_BUS_DEVICE_NAME); - sprintf(device->pnp.device_class, "%s", ACPI_BUS_CLASS); + strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); + strcpy(device->pnp.device_class, ACPI_BUS_CLASS); } if (hid) { - sprintf(device->pnp.hardware_id, "%s", hid); + strcpy(device->pnp.hardware_id, hid); device->flags.hardware_id = 1; } if (uid) { - sprintf(device->pnp.unique_id, "%s", uid); + strcpy(device->pnp.unique_id, uid); device->flags.unique_id = 1; } if (cid_list) { --- diff/drivers/acpi/tables.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/acpi/tables.c 2004-02-09 10:39:52.000000000 +0000 @@ -58,6 +58,7 @@ [ACPI_SSDT] = "SSDT", [ACPI_SPMI] = "SPMI", [ACPI_HPET] = "HPET", + [ACPI_MCFG] = "MCFG", }; static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" }; @@ -302,13 +303,14 @@ enum acpi_table_id id, unsigned long madt_size, int entry_id, - acpi_madt_entry_handler handler) + acpi_madt_entry_handler handler, + unsigned int max_entries) { void *madt = NULL; - acpi_table_entry_header *entry = NULL; - unsigned long count = 0; - unsigned long madt_end = 0; - unsigned int i = 0; + acpi_table_entry_header *entry; + unsigned int count = 0; + unsigned long madt_end; + unsigned int i; if (!handler) return -EINVAL; @@ -342,13 +344,18 @@ ((unsigned long) madt + madt_size); while (((unsigned long) entry) < madt_end) { - if (entry->type == entry_id) { - count++; + if (entry->type == entry_id && + (!max_entries || count++ < max_entries)) handler(entry); - } + entry = (acpi_table_entry_header *) ((unsigned long) entry + entry->length); } + if (max_entries && count > max_entries) { + printk(KERN_WARNING PREFIX "[%s:0x%02x] ignored %i entries of " + "%i found\n", acpi_table_signatures[id], entry_id, + count - max_entries, count); + } return count; } @@ -357,10 +364,11 @@ int __init acpi_table_parse_madt ( enum acpi_madt_entry_id id, - acpi_madt_entry_handler handler) + acpi_madt_entry_handler handler, + unsigned int max_entries) { return acpi_table_parse_madt_family(ACPI_APIC, sizeof(struct acpi_table_madt), - id, handler); + id, handler, max_entries); } @@ -585,4 +593,3 @@ return 0; } - --- diff/drivers/acpi/thermal.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/acpi/thermal.c 2004-02-09 10:39:52.000000000 +0000 @@ -1246,9 +1246,9 @@ memset(tz, 0, sizeof(struct acpi_thermal)); tz->handle = device->handle; - sprintf(tz->name, "%s", device->pnp.bus_id); - sprintf(acpi_device_name(device), "%s", ACPI_THERMAL_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_THERMAL_CLASS); + strcpy(tz->name, device->pnp.bus_id); + strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); acpi_driver_data(device) = tz; result = acpi_thermal_get_info(tz); --- diff/drivers/atm/atmtcp.c 2003-10-09 09:47:33.000000000 +0100 +++ source/drivers/atm/atmtcp.c 2004-02-09 10:39:52.000000000 +0000 @@ -255,7 +255,7 @@ dev_data = PRIV(atmtcp_dev); dev_data->vcc = NULL; if (dev_data->persist) return; - PRIV(atmtcp_dev) = NULL; + atmtcp_dev->dev_data = NULL; kfree(dev_data); shutdown_atm_dev(atmtcp_dev); vcc->dev_data = NULL; @@ -380,7 +380,7 @@ } dev->ci_range.vpi_bits = MAX_VPI_BITS; dev->ci_range.vci_bits = MAX_VCI_BITS; - PRIV(dev) = dev_data; + dev->dev_data = dev_data; PRIV(dev)->vcc = NULL; PRIV(dev)->persist = persist; if (result) *result = dev; --- diff/drivers/atm/eni.c 2003-10-09 09:47:33.000000000 +0100 +++ source/drivers/atm/eni.c 2004-02-09 10:39:52.000000000 +0000 @@ -1875,7 +1875,7 @@ DPRINTK("eni_close: done waiting\n"); /* deallocate memory */ kfree(ENI_VCC(vcc)); - ENI_VCC(vcc) = NULL; + vcc->dev_data = NULL; clear_bit(ATM_VF_ADDR,&vcc->flags); /*foo();*/ } @@ -1891,7 +1891,8 @@ DPRINTK(">eni_open\n"); EVENT("eni_open\n",0,0); - if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ENI_VCC(vcc) = NULL; + if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) + vcc->dev_data = NULL; eni_dev = ENI_DEV(vcc->dev); if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) set_bit(ATM_VF_ADDR,&vcc->flags); @@ -1902,7 +1903,7 @@ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) { eni_vcc = kmalloc(sizeof(struct eni_vcc),GFP_KERNEL); if (!eni_vcc) return -ENOMEM; - ENI_VCC(vcc) = eni_vcc; + vcc->dev_data = eni_vcc; eni_vcc->tx = NULL; /* for eni_close after open_rx */ if ((error = open_rx_first(vcc))) { eni_close(vcc); @@ -2230,7 +2231,7 @@ if (!dev) goto out2; pci_set_drvdata(pci_dev, dev); eni_dev->pci_dev = pci_dev; - ENI_DEV(dev) = eni_dev; + dev->dev_data = eni_dev; eni_dev->asic = ent->driver_data; error = eni_do_init(dev); if (error) goto out3; --- diff/drivers/atm/fore200e.c 2003-10-27 09:20:37.000000000 +0000 +++ source/drivers/atm/fore200e.c 2004-02-09 10:39:52.000000000 +0000 @@ -1417,7 +1417,7 @@ return -ENOMEM; } - FORE200E_VCC(vcc) = fore200e_vcc; + vcc->dev_data = fore200e_vcc; if (fore200e_activate_vcin(fore200e, 1, vcc, vcc->qos.rxtp.max_sdu) < 0) { kfree(fore200e_vcc); @@ -2482,7 +2482,7 @@ return -ENODEV; } - FORE200E_DEV(atm_dev) = fore200e; + atm_dev->dev_data = fore200e; fore200e->atm_dev = atm_dev; atm_dev->ci_range.vpi_bits = 8; --- diff/drivers/atm/he.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/atm/he.c 2004-02-09 10:39:52.000000000 +0000 @@ -380,7 +380,7 @@ he_dev->pci_dev = pci_dev; he_dev->atm_dev = atm_dev; he_dev->atm_dev->dev_data = he_dev; - HE_DEV(atm_dev) = he_dev; + atm_dev->dev_data = he_dev; he_dev->number = atm_dev->number; if (he_start(atm_dev)) { he_stop(he_dev); @@ -2361,7 +2361,7 @@ init_waitqueue_head(&he_vcc->rx_waitq); init_waitqueue_head(&he_vcc->tx_waitq); - HE_VCC(vcc) = he_vcc; + vcc->dev_data = he_vcc; if (vcc->qos.txtp.traffic_class != ATM_NONE) { int pcr_goal; --- diff/drivers/atm/idt77105.c 2003-05-21 11:49:54.000000000 +0100 +++ source/drivers/atm/idt77105.c 2004-02-09 10:39:52.000000000 +0000 @@ -265,7 +265,7 @@ { unsigned long flags; - if (!(PRIV(dev) = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL))) + if (!(dev->dev_data = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL))) return -ENOMEM; PRIV(dev)->dev = dev; spin_lock_irqsave(&idt77105_priv_lock, flags); @@ -343,7 +343,7 @@ else idt77105_all = walk->next; dev->phy = NULL; - PRIV(dev) = NULL; + dev->dev_data = NULL; kfree(walk); break; } --- diff/drivers/atm/iphase.c 2003-10-09 09:47:33.000000000 +0100 +++ source/drivers/atm/iphase.c 2004-02-09 10:39:52.000000000 +0000 @@ -1754,7 +1754,7 @@ (iadev->tx_buf_sz - sizeof(struct cpcs_trailer))){ printk("IA: SDU size over (%d) the configured SDU size %d\n", vcc->qos.txtp.max_sdu,iadev->tx_buf_sz); - INPH_IA_VCC(vcc) = NULL; + vcc->dev_data = NULL; kfree(ia_vcc); return -EINVAL; } @@ -2671,7 +2671,7 @@ } kfree(INPH_IA_VCC(vcc)); ia_vcc = NULL; - INPH_IA_VCC(vcc) = NULL; + vcc->dev_data = NULL; clear_bit(ATM_VF_ADDR,&vcc->flags); return; } @@ -2684,7 +2684,7 @@ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) { IF_EVENT(printk("ia: not partially allocated resources\n");) - INPH_IA_VCC(vcc) = NULL; + vcc->dev_data = NULL; } iadev = INPH_IA_DEV(vcc->dev); if (vcc->vci != ATM_VPI_UNSPEC && vcc->vpi != ATM_VCI_UNSPEC) @@ -2700,7 +2700,7 @@ /* Device dependent initialization */ ia_vcc = kmalloc(sizeof(*ia_vcc), GFP_KERNEL); if (!ia_vcc) return -ENOMEM; - INPH_IA_VCC(vcc) = ia_vcc; + vcc->dev_data = ia_vcc; if ((error = open_rx(vcc))) { @@ -3196,7 +3196,7 @@ ret = -ENOMEM; goto err_out_disable_dev; } - INPH_IA_DEV(dev) = iadev; + dev->dev_data = iadev; IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", dev->number);) IF_INIT(printk("dev_id = 0x%x iadev->LineRate = %d \n", (u32)dev, iadev->LineRate);) --- diff/drivers/atm/suni.c 2003-05-21 11:49:54.000000000 +0100 +++ source/drivers/atm/suni.c 2004-02-09 10:39:52.000000000 +0000 @@ -230,7 +230,7 @@ unsigned long flags; int first; - if (!(PRIV(dev) = kmalloc(sizeof(struct suni_priv),GFP_KERNEL))) + if (!(dev->dev_data = kmalloc(sizeof(struct suni_priv),GFP_KERNEL))) return -ENOMEM; PRIV(dev)->dev = dev; --- diff/drivers/atm/uPD98402.c 2003-09-30 15:46:12.000000000 +0100 +++ source/drivers/atm/uPD98402.c 2004-02-09 10:39:52.000000000 +0000 @@ -211,7 +211,7 @@ static int uPD98402_start(struct atm_dev *dev) { DPRINTK("phy_start\n"); - if (!(PRIV(dev) = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL))) + if (!(dev->dev_data = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL))) return -ENOMEM; spin_lock_init(&PRIV(dev)->lock); memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats)); --- diff/drivers/atm/zatm.c 2003-10-09 09:47:33.000000000 +0100 +++ source/drivers/atm/zatm.c 2004-02-09 10:39:52.000000000 +0000 @@ -1368,7 +1368,7 @@ DPRINTK("zatm_close: done waiting\n"); /* deallocate memory */ kfree(ZATM_VCC(vcc)); - ZATM_VCC(vcc) = NULL; + vcc->dev_data = NULL; clear_bit(ATM_VF_ADDR,&vcc->flags); } @@ -1383,7 +1383,8 @@ DPRINTK(">zatm_open\n"); zatm_dev = ZATM_DEV(vcc->dev); - if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ZATM_VCC(vcc) = NULL; + if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) + vcc->dev_data = NULL; if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) set_bit(ATM_VF_ADDR,&vcc->flags); if (vcc->qos.aal != ATM_AAL5) return -EINVAL; /* @@@ AAL0 */ @@ -1395,7 +1396,7 @@ clear_bit(ATM_VF_ADDR,&vcc->flags); return -ENOMEM; } - ZATM_VCC(vcc) = zatm_vcc; + vcc->dev_data = zatm_vcc; ZATM_VCC(vcc)->tx_chan = 0; /* for zatm_close after open_rx */ if ((error = open_rx_first(vcc))) { zatm_close(vcc); @@ -1597,7 +1598,7 @@ dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL); if (!dev) break; zatm_dev->pci_dev = pci_dev; - ZATM_DEV(dev) = zatm_dev; + dev->dev_data = zatm_dev; zatm_dev->copper = type; if (zatm_init(dev) || zatm_start(dev)) { atm_dev_deregister(dev); --- diff/drivers/base/Makefile 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/base/Makefile 2004-02-09 10:39:52.000000000 +0000 @@ -3,6 +3,7 @@ obj-y := core.o sys.o interface.o bus.o \ driver.o class.o class_simple.o platform.o \ cpu.o firmware.o init.o map.o +obj-$(CONFIG_PCI) += dmapool.o obj-y += power/ obj-$(CONFIG_FW_LOADER) += firmware_class.o -obj-$(CONFIG_NUMA) += node.o memblk.o +obj-$(CONFIG_NUMA) += node.o --- diff/drivers/base/class_simple.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/base/class_simple.c 2004-02-09 10:39:52.000000000 +0000 @@ -170,6 +170,24 @@ EXPORT_SYMBOL(class_simple_device_add); /** + * class_simple_set_hotplug - set the hotplug callback in the embedded struct class + * @cs: pointer to the struct class_simple to hold the pointer + * @hotplug: function pointer to the hotplug function + * + * Implement and set a hotplug function to add environment variables specific to this + * class on the hotplug event. + */ +int class_simple_set_hotplug(struct class_simple *cs, + int (*hotplug)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size)) +{ + if ((cs == NULL) || (IS_ERR(cs))) + return -ENODEV; + cs->class.hotplug = hotplug; + return 0; +} +EXPORT_SYMBOL(class_simple_set_hotplug); + +/** * class_simple_device_remove - removes a class device that was created with class_simple_device_add() * @dev: the dev_t of the device that was previously registered. * --- diff/drivers/base/core.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/base/core.c 2004-02-09 10:39:52.000000000 +0000 @@ -76,7 +76,6 @@ static void device_release(struct kobject * kobj) { struct device * dev = to_dev(kobj); - struct completion * c = dev->complete; if (dev->release) dev->release(dev); @@ -86,8 +85,6 @@ dev->bus_id); WARN_ON(1); } - if (c) - complete(c); } static struct kobj_type ktype_device = { @@ -197,6 +194,7 @@ INIT_LIST_HEAD(&dev->children); INIT_LIST_HEAD(&dev->driver_list); INIT_LIST_HEAD(&dev->bus_list); + INIT_LIST_HEAD(&dev->dma_pools); } /** @@ -355,25 +353,6 @@ /** - * device_unregister_wait - Unregister device and wait for it to be freed. - * @dev: Device to unregister. - * - * For the cases where the caller needs to wait for all references to - * be dropped from the device before continuing (e.g. modules with - * statically allocated devices), this function uses a completion struct - * to wait, along with a matching complete() in device_release() above. - */ - -void device_unregister_wait(struct device * dev) -{ - struct completion c; - init_completion(&c); - dev->complete = &c; - device_unregister(dev); - wait_for_completion(&c); -} - -/** * device_for_each_child - device child iterator. * @dev: parent struct device. * @data: data for the callback. @@ -421,7 +400,6 @@ EXPORT_SYMBOL(device_del); EXPORT_SYMBOL(device_unregister); -EXPORT_SYMBOL(device_unregister_wait); EXPORT_SYMBOL(get_device); EXPORT_SYMBOL(put_device); EXPORT_SYMBOL(device_find); --- diff/drivers/base/cpu.c 2003-10-27 09:20:43.000000000 +0000 +++ source/drivers/base/cpu.c 2004-02-09 10:39:52.000000000 +0000 @@ -7,6 +7,7 @@ #include #include #include +#include struct sysdev_class cpu_sysdev_class = { @@ -14,6 +15,46 @@ }; EXPORT_SYMBOL(cpu_sysdev_class); +#ifdef CONFIG_HOTPLUG_CPU +static ssize_t show_online(struct sys_device *dev, char *buf) +{ + struct cpu *cpu = container_of(dev, struct cpu, sysdev); + + return sprintf(buf, "%u\n", !!cpu_online(cpu->sysdev.id)); +} + +static ssize_t store_online(struct sys_device *dev, const char *buf, + size_t count) +{ + struct cpu *cpu = container_of(dev, struct cpu, sysdev); + ssize_t ret; + + switch (buf[0]) { + case '0': + ret = cpu_down(cpu->sysdev.id); + break; + case '1': + ret = cpu_up(cpu->sysdev.id); + break; + default: + ret = -EINVAL; + } + + if (ret >= 0) + ret = count; + return ret; +} +static SYSDEV_ATTR(online, 0600, show_online, store_online); + +static void __init register_cpu_control(struct cpu *cpu) +{ + sysdev_create_file(&cpu->sysdev, &attr_online); +} +#else /* ... !CONFIG_HOTPLUG_CPU */ +static void __init register_cpu_control(struct cpu *cpu) +{ +} +#endif /* CONFIG_HOTPLUG_CPU */ /* * register_cpu - Setup a driverfs device for a CPU. @@ -34,6 +75,8 @@ error = sysfs_create_link(&root->sysdev.kobj, &cpu->sysdev.kobj, kobject_name(&cpu->sysdev.kobj)); + if (!error) + register_cpu_control(cpu); return error; } --- diff/drivers/block/Kconfig.iosched 2003-10-09 09:47:16.000000000 +0100 +++ source/drivers/block/Kconfig.iosched 2004-02-09 10:39:52.000000000 +0000 @@ -27,3 +27,10 @@ a disk at any one time, its behaviour is almost identical to the anticipatory I/O scheduler and so is a good choice. +config IOSCHED_CFQ + bool "CFQ I/O scheduler" if EMBEDDED + default y + ---help--- + The CFQ I/O scheduler tries to distribute bandwidth equally + among all processes in the system. It should provide a fair + working environment, suitable for desktop systems. --- diff/drivers/block/Makefile 2003-10-27 09:20:37.000000000 +0000 +++ source/drivers/block/Makefile 2004-02-09 10:39:52.000000000 +0000 @@ -18,6 +18,7 @@ obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o obj-$(CONFIG_IOSCHED_AS) += as-iosched.o obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o +obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o obj-$(CONFIG_MAC_FLOPPY) += swim3.o obj-$(CONFIG_BLK_DEV_FD) += floppy.o obj-$(CONFIG_BLK_DEV_FD98) += floppy98.o --- diff/drivers/block/cciss.c 2003-10-09 09:47:33.000000000 +0100 +++ source/drivers/block/cciss.c 2004-02-09 10:39:52.000000000 +0000 @@ -45,12 +45,14 @@ #include #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "Compaq CISS Driver (v 2.5.0)" -#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,5,0) +#define DRIVER_NAME "Compaq CISS Driver (v 2.6.0)" +#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,0) /* Embedded module documentation macros - see modules.h */ -MODULE_AUTHOR("Charles M. White III - Compaq Computer Corporation"); -MODULE_DESCRIPTION("Driver for Compaq Smart Array Controller 5xxx v. 2.5.0"); +MODULE_AUTHOR("Hewlett-Packard Company"); +MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.0"); +MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" + " SA6i"); MODULE_LICENSE("GPL"); #include "cciss_cmd.h" @@ -75,6 +77,8 @@ 0x0E11, 0x409C, 0, 0, 0}, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409D, 0, 0, 0}, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, + 0x0E11, 0x4091, 0, 0, 0}, {0,} }; MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); @@ -94,6 +98,7 @@ { 0x409B0E11, "Smart Array 642", &SA5_access}, { 0x409C0E11, "Smart Array 6400", &SA5_access}, { 0x409D0E11, "Smart Array 6400 EM", &SA5_access}, + { 0x40910E11, "Smart Array 6i", &SA5_access}, }; /* How long to wait (in millesconds) for board to go into simple mode */ @@ -103,7 +108,7 @@ /*define how many times we will try a command because of bus resets */ #define MAX_CMD_RETRIES 3 -#define READ_AHEAD 128 +#define READ_AHEAD 256 #define NR_CMDS 384 /* #commands that can be outstanding */ #define MAX_CTLR 8 @@ -151,6 +156,11 @@ /* * Report information about this controller. */ +#define ENG_GIG 1048576000 +#define ENG_GIG_FACTOR (ENG_GIG/512) +#define RAID_UNKNOWN 6 +static const char *raid_label[] = {"0","4","1(0+1)","5","5+1","ADG", + "UNKNOWN"}; #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_cciss; @@ -163,49 +173,80 @@ int size, i, ctlr; ctlr_info_t *h = (ctlr_info_t*)data; drive_info_struct *drv; + unsigned long flags; + unsigned int vol_sz, vol_sz_frac; ctlr = h->ctlr; - size = sprintf(buffer, "%s: Compaq %s Controller\n" - " Board ID: 0x%08lx\n" - " Firmware Version: %c%c%c%c\n" - " Memory Address: 0x%08lx\n" - " IRQ: %d\n" - " Logical drives: %d\n" - " Highest Logical Volume ID: %d\n" - " Current Q depth: %d\n" - " Max Q depth since init: %d\n" - " Max # commands on controller since init: %d\n" - " Max SG entries since init: %d\n\n", + + /* prevent displaying bogus info during configuration + * or deconfiguration of a logical volume + */ + spin_lock_irqsave(CCISS_LOCK(ctlr), flags); + if (h->busy_configuring) { + spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); + return -EBUSY; + } + h->busy_configuring = 1; + spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); + + size = sprintf(buffer, "%s: HP %s Controller\n" + "Board ID: 0x%08lx\n" + "Firmware Version: %c%c%c%c\n" + "IRQ: %d\n" + "Logical drives: %d\n" + "Current Q depth: %d\n" + "Current # commands on controller: %d\n" + "Max Q depth since init: %d\n" + "Max # commands on controller since init: %d\n" + "Max SG entries since init: %d\n\n", h->devname, h->product_name, (unsigned long)h->board_id, h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3], - (unsigned long)h->vaddr, (unsigned int)h->intr, h->num_luns, - h->highest_lun, - h->Qdepth, h->maxQsinceinit, h->max_outstanding, h->maxSG); + h->Qdepth, h->commands_outstanding, + h->maxQsinceinit, h->max_outstanding, h->maxSG); pos += size; len += size; cciss_proc_tape_report(ctlr, buffer, &pos, &len); for(i=0; ihighest_lun; i++) { + sector_t tmp; + drv = &h->drv[i]; if (drv->block_size == 0) continue; - size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%llu\n", - ctlr, i, drv->block_size, (unsigned long long)drv->nr_blocks); + vol_sz = drv->nr_blocks; + sector_div(vol_sz, ENG_GIG_FACTOR); + + /* + * Awkwardly do this: + * vol_sz_frac = + * (drv->nr_blocks%ENG_GIG_FACTOR)*100/ENG_GIG_FACTOR; + */ + tmp = drv->nr_blocks; + vol_sz_frac = sector_div(tmp, ENG_GIG_FACTOR); + + /* Now, vol_sz_frac = (drv->nr_blocks%ENG_GIG_FACTOR) */ + + vol_sz_frac *= 100; + sector_div(vol_sz_frac, ENG_GIG_FACTOR); + + if (drv->raid_level > 5) + drv->raid_level = RAID_UNKNOWN; + size = sprintf(buffer+len, "cciss/c%dd%d:" + "\t%4d.%02dGB\tRAID %s\n", + ctlr, i, vol_sz,vol_sz_frac, + raid_label[drv->raid_level]); pos += size; len += size; } - size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n", - h->nr_allocs, h->nr_frees); - pos += size; len += size; - *eof = 1; *start = buffer+offset; len -= offset; if (len>length) len = length; + h->busy_configuring = 0; return len; } @@ -1304,7 +1345,7 @@ *total_size = 0; *block_size = BLOCK_SIZE; } - printk(KERN_INFO " blocks= %d block_size= %d\n", + printk(KERN_INFO " blocks= %u block_size= %d\n", *total_size, *block_size); return; } @@ -1978,7 +2019,7 @@ /* Is this interrupt for us? */ - if ( h->access.intr_pending(h) == 0) + if (( h->access.intr_pending(h) == 0) || (h->interrupts_enabled == 0)) return IRQ_NONE; /* @@ -2078,18 +2119,61 @@ c->io_mem_addr = 0; c->io_mem_length = 0; } + +static int find_PCI_BAR_index(struct pci_dev *pdev, + unsigned long pci_bar_addr) +{ + int i, offset, mem_type, bar_type; + if (pci_bar_addr == PCI_BASE_ADDRESS_0) /* looking for BAR zero? */ + return 0; + offset = 0; + for (i=0; iirq; __u32 board_id, scratchpad = 0; - int cfg_offset; - int cfg_base_addr; - int cfg_base_addr_index; + __u64 cfg_offset; + __u32 cfg_base_addr; + __u64 cfg_base_addr_index; int i; + /* check to see if controller has been disabled */ + /* BEFORE trying to enable it */ + (void) pci_read_config_word(pdev, PCI_COMMAND,&command); + if(!(command & 0x02)) + { + printk(KERN_WARNING "cciss: controller appears to be disabled\n"); + return(-1); + } + if (pci_enable_device(pdev)) { printk(KERN_ERR "cciss: Unable to Enable PCI device\n"); @@ -2101,38 +2185,19 @@ return(-1); } - vendor_id = pdev->vendor; - device_id = pdev->device; - irq = pdev->irq; - - for(i=0; i<6; i++) - addr[i] = pdev->resource[i].start; - - (void) pci_read_config_word(pdev, PCI_COMMAND,&command); - (void) pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); - (void) pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, - &cache_line_size); - (void) pci_read_config_byte(pdev, PCI_LATENCY_TIMER, - &latency_timer); - (void) pci_read_config_dword(pdev, PCI_SUBSYSTEM_VENDOR_ID, - &board_id); - - /* check to see if controller has been disabled */ - if(!(command & 0x02)) - { - printk(KERN_WARNING "cciss: controller appears to be disabled\n"); - return(-1); - } + subsystem_vendor_id = pdev->subsystem_vendor; + subsystem_device_id = pdev->subsystem_device; + board_id = (((__u32) (subsystem_device_id << 16) & 0xffff0000) | + subsystem_vendor_id); /* search for our IO range so we can protect it */ - for(i=0; i<6; i++) + for(i=0; iresource[i].flags & 0x01 ) - { - c->io_mem_addr = pdev->resource[i].start; - c->io_mem_length = pdev->resource[i].end - - pdev->resource[i].start +1; + if( pci_resource_flags(pdev, i) & 0x01 ) { + c->io_mem_addr = pci_resource_start(pdev, i); + c->io_mem_length = pci_resource_end(pdev, i) - + pci_resource_start(pdev, i) +1; #ifdef CCISS_DEBUG printk("IO value found base_addr[%d] %lx %lx\n", i, c->io_mem_addr, c->io_mem_length); @@ -2151,15 +2216,8 @@ } #ifdef CCISS_DEBUG - printk("vendor_id = %x\n", vendor_id); - printk("device_id = %x\n", device_id); printk("command = %x\n", command); - for(i=0; i<6; i++) - printk("addr[%d] = %x\n", i, addr[i]); - printk("revision = %x\n", revision); printk("irq = %x\n", irq); - printk("cache_line_size = %x\n", cache_line_size); - printk("latency_timer = %x\n", latency_timer); printk("board_id = %x\n", board_id); #endif /* CCISS_DEBUG */ @@ -2170,7 +2228,7 @@ * table */ - c->paddr = addr[0] ; /* addressing mode bits already removed */ + c->paddr = pci_resource_start(pdev, 0); /* addressing mode bits already removed */ #ifdef CCISS_DEBUG printk("address 0 = %x\n", c->paddr); #endif /* CCISS_DEBUG */ @@ -2192,22 +2250,27 @@ /* get the address index number */ cfg_base_addr = readl(c->vaddr + SA5_CTCFG_OFFSET); - /* I am not prepared to deal with a 64 bit address value */ - cfg_base_addr &= 0xffff; + cfg_base_addr &= (__u32) 0x0000ffff; #ifdef CCISS_DEBUG printk("cfg base address = %x\n", cfg_base_addr); #endif /* CCISS_DEBUG */ - cfg_base_addr_index = (cfg_base_addr - PCI_BASE_ADDRESS_0)/4; + cfg_base_addr_index = + find_PCI_BAR_index(pdev, cfg_base_addr); #ifdef CCISS_DEBUG printk("cfg base address index = %x\n", cfg_base_addr_index); #endif /* CCISS_DEBUG */ + if (cfg_base_addr_index == -1) { + printk(KERN_WARNING "cciss: Cannot find cfg_base_addr_index\n"); + release_io_mem(c); + return -1; + } cfg_offset = readl(c->vaddr + SA5_CTMEM_OFFSET); #ifdef CCISS_DEBUG printk("cfg offset = %x\n", cfg_offset); #endif /* CCISS_DEBUG */ c->cfgtable = (CfgTable_struct *) - remap_pci_mem((addr[cfg_base_addr_index] & 0xfffffff0) + remap_pci_mem(pci_resource_start(pdev, cfg_base_addr_index) + cfg_offset, sizeof(CfgTable_struct)); c->board_id = board_id; @@ -2236,6 +2299,17 @@ printk("Does not appear to be a valid CISS config table\n"); return -1; } + +#ifdef CONFIG_X86 +{ + /* Need to enable prefetch in the SCSI core for 6400 in x86 */ + __u32 prefetch; + prefetch = readl(&(c->cfgtable->SCSI_Prefetch)); + prefetch |= 0x100; + writel(prefetch, &(c->cfgtable->SCSI_Prefetch)); +} +#endif + #ifdef CCISS_DEBUG printk("Trying to put board into Simple mode\n"); #endif /* CCISS_DEBUG */ @@ -2501,6 +2575,7 @@ if (!q) goto clean4; + q->backing_dev_info.ra_pages = READ_AHEAD; hba[i]->queue = q; q->queuedata = hba[i]; @@ -2610,7 +2685,6 @@ pci_set_drvdata(pdev, NULL); iounmap((void*)hba[i]->vaddr); cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ - blk_cleanup_queue(hba[i]->queue); unregister_blkdev(COMPAQ_CISS_MAJOR+i, hba[i]->devname); remove_proc_entry(hba[i]->devname, proc_cciss); @@ -2621,6 +2695,7 @@ del_gendisk(disk); } + blk_cleanup_queue(hba[i]->queue); pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct), hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle); pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct), @@ -2646,7 +2721,7 @@ printk(KERN_INFO DRIVER_NAME "\n"); /* Register for our PCI devices */ - return pci_register_driver(&cciss_pci_driver); + return pci_module_init(&cciss_pci_driver); } static int __init init_cciss_module(void) --- diff/drivers/block/cciss.h 2003-08-20 14:16:27.000000000 +0100 +++ source/drivers/block/cciss.h 2004-02-09 10:39:52.000000000 +0000 @@ -32,6 +32,7 @@ int heads; int sectors; int cylinders; + int raid_level; } drive_info_struct; struct ctlr_info @@ -42,13 +43,13 @@ char firm_ver[4]; // Firmware version struct pci_dev *pdev; __u32 board_id; - ulong vaddr; - __u32 paddr; + unsigned long vaddr; + unsigned long paddr; unsigned long io_mem_addr; unsigned long io_mem_length; CfgTable_struct *cfgtable; int intr; - + int interrupts_enabled; int max_commands; int commands_outstanding; int max_outstanding; /* Debug */ @@ -78,6 +79,7 @@ unsigned long *cmd_pool_bits; int nr_allocs; int nr_frees; + int busy_configuring; // Disk structures we need to pass back struct gendisk *gendisk[NWD]; @@ -134,9 +136,11 @@ { if (val) { /* Turn interrupts on */ + h->interrupts_enabled = 1; writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); } else /* Turn them off */ { + h->interrupts_enabled = 0; writel( SA5_INTR_OFF, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); } @@ -150,9 +154,11 @@ { if (val) { /* Turn interrupts on */ + h->interrupts_enabled = 1; writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); } else /* Turn them off */ { + h->interrupts_enabled = 0; writel( SA5B_INTR_OFF, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); } --- diff/drivers/block/cciss_cmd.h 2003-05-21 11:49:45.000000000 +0100 +++ source/drivers/block/cciss_cmd.h 2004-02-09 10:39:52.000000000 +0000 @@ -265,6 +265,7 @@ DWORD Reserved; BYTE ServerName[16]; DWORD HeartBeat; + DWORD SCSI_Prefetch; } CfgTable_struct; #pragma pack() #endif // CCISS_CMD_H --- diff/drivers/block/cryptoloop.c 2003-08-26 10:00:52.000000000 +0100 +++ source/drivers/block/cryptoloop.c 2004-02-09 10:39:52.000000000 +0000 @@ -87,43 +87,49 @@ static int -cryptoloop_transfer_ecb(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size, sector_t IV) +cryptoloop_transfer_ecb(struct loop_device *lo, int cmd, + struct page *raw_page, unsigned raw_off, + struct page *loop_page, unsigned loop_off, + int size, sector_t IV) { struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data; struct scatterlist sg_out = { 0, }; struct scatterlist sg_in = { 0, }; encdec_ecb_t encdecfunc; - char const *in; - char *out; + struct page *in_page, *out_page; + unsigned in_offs, out_offs; if (cmd == READ) { - in = raw_buf; - out = loop_buf; + in_page = raw_page; + in_offs = raw_off; + out_page = loop_page; + out_offs = loop_off; encdecfunc = tfm->crt_u.cipher.cit_decrypt; } else { - in = loop_buf; - out = raw_buf; + in_page = loop_page; + in_offs = loop_off; + out_page = raw_page; + out_offs = raw_off; encdecfunc = tfm->crt_u.cipher.cit_encrypt; } while (size > 0) { const int sz = min(size, LOOP_IV_SECTOR_SIZE); - sg_in.page = virt_to_page(in); - sg_in.offset = (unsigned long)in & ~PAGE_MASK; + sg_in.page = in_page; + sg_in.offset = in_offs; sg_in.length = sz; - sg_out.page = virt_to_page(out); - sg_out.offset = (unsigned long)out & ~PAGE_MASK; + sg_out.page = out_page; + sg_out.offset = out_offs; sg_out.length = sz; encdecfunc(tfm, &sg_out, &sg_in, sz); size -= sz; - in += sz; - out += sz; + in_offs += sz; + out_offs += sz; } return 0; @@ -135,24 +141,30 @@ unsigned int nsg, u8 *iv); static int -cryptoloop_transfer_cbc(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size, sector_t IV) +cryptoloop_transfer_cbc(struct loop_device *lo, int cmd, + struct page *raw_page, unsigned raw_off, + struct page *loop_page, unsigned loop_off, + int size, sector_t IV) { struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data; struct scatterlist sg_out = { 0, }; struct scatterlist sg_in = { 0, }; encdec_cbc_t encdecfunc; - char const *in; - char *out; + struct page *in_page, *out_page; + unsigned in_offs, out_offs; if (cmd == READ) { - in = raw_buf; - out = loop_buf; + in_page = raw_page; + in_offs = raw_off; + out_page = loop_page; + out_offs = loop_off; encdecfunc = tfm->crt_u.cipher.cit_decrypt_iv; } else { - in = loop_buf; - out = raw_buf; + in_page = loop_page; + in_offs = loop_off; + out_page = raw_page; + out_offs = raw_off; encdecfunc = tfm->crt_u.cipher.cit_encrypt_iv; } @@ -161,39 +173,43 @@ u32 iv[4] = { 0, }; iv[0] = cpu_to_le32(IV & 0xffffffff); - sg_in.page = virt_to_page(in); - sg_in.offset = offset_in_page(in); + sg_in.page = in_page; + sg_in.offset = in_offs; sg_in.length = sz; - sg_out.page = virt_to_page(out); - sg_out.offset = offset_in_page(out); + sg_out.page = out_page; + sg_out.offset = out_offs; sg_out.length = sz; encdecfunc(tfm, &sg_out, &sg_in, sz, (u8 *)iv); IV++; size -= sz; - in += sz; - out += sz; + in_offs += sz; + out_offs += sz; } return 0; } static int -cryptoloop_transfer(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size, sector_t IV) +cryptoloop_transfer(struct loop_device *lo, int cmd, + struct page *raw_page, unsigned raw_off, + struct page *loop_page, unsigned loop_off, + int size, sector_t IV) { struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data; if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB) { lo->transfer = cryptoloop_transfer_ecb; - return cryptoloop_transfer_ecb(lo, cmd, raw_buf, loop_buf, size, IV); + return cryptoloop_transfer_ecb(lo, cmd, raw_page, raw_off, + loop_page, loop_off, size, IV); } if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_CBC) { lo->transfer = cryptoloop_transfer_cbc; - return cryptoloop_transfer_cbc(lo, cmd, raw_buf, loop_buf, size, IV); + return cryptoloop_transfer_cbc(lo, cmd, raw_page, raw_off, + loop_page, loop_off, size, IV); } /* This is not supposed to happen */ --- diff/drivers/block/floppy.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/block/floppy.c 2004-02-09 10:39:52.000000000 +0000 @@ -4376,6 +4376,7 @@ /* to be cleaned up... */ disks[drive]->private_data = (void*)(long)drive; disks[drive]->queue = floppy_queue; + disks[drive]->flags |= GENHD_FL_REMOVABLE; add_disk(disks[drive]); } --- diff/drivers/block/genhd.c 2004-01-19 10:22:56.000000000 +0000 +++ source/drivers/block/genhd.c 2004-02-09 10:39:52.000000000 +0000 @@ -260,8 +260,10 @@ if (&sgp->kobj.entry == block_subsys.kset.list.next) seq_puts(part, "major minor #blocks name\n\n"); - /* Don't show non-partitionable devices or empty devices */ - if (!get_capacity(sgp) || sgp->minors == 1) + /* Don't show non-partitionable removeable devices or empty devices */ + if (!get_capacity(sgp) || + (sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE)) + ) return 0; /* show the full disk and all non-0 size partitions of it */ --- diff/drivers/block/ll_rw_blk.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/block/ll_rw_blk.c 2004-02-09 10:39:52.000000000 +0000 @@ -27,6 +27,7 @@ #include #include #include +#include static void blk_unplug_work(void *data); static void blk_unplug_timeout(unsigned long data); @@ -521,10 +522,10 @@ { int bits, i; - if (depth > q->nr_requests * 2) { - depth = q->nr_requests * 2; - printk(KERN_ERR "%s: adjusted depth to %d\n", - __FUNCTION__, depth); + if (depth > q->nr_requests / 2) { + q->nr_requests = depth * 2; + printk(KERN_INFO "%s: large TCQ depth: adjusted nr_requests " + "to %lu\n", __FUNCTION__, q->nr_requests); } tags->tag_index = kmalloc(depth * sizeof(struct request *), GFP_ATOMIC); @@ -1334,6 +1335,8 @@ &iosched_as; #elif defined(CONFIG_IOSCHED_DEADLINE) &iosched_deadline; +#elif defined(CONFIG_IOSCHED_CFQ) + &iosched_cfq; #elif defined(CONFIG_IOSCHED_NOOP) &elevator_noop; #else @@ -1352,6 +1355,10 @@ if (!strcmp(str, "as")) chosen_elevator = &iosched_as; #endif +#ifdef CONFIG_IOSCHED_CFQ + if (!strcmp(str, "cfq")) + chosen_elevator = &iosched_cfq; +#endif #ifdef CONFIG_IOSCHED_NOOP if (!strcmp(str, "noop")) chosen_elevator = &elevator_noop; @@ -1884,18 +1891,22 @@ * Waits for up to @timeout jiffies for a queue (any queue) to exit congestion. * If no queues are congested then just wait for the next request to be * returned. + * + * Returns the number of jiffies remaining, this is zero, unless we returned + * before @timeout expired. */ -void blk_congestion_wait(int rw, long timeout) +long blk_congestion_wait(int rw, long timeout) { + long ret; DEFINE_WAIT(wait); wait_queue_head_t *wqh = &congestion_wqh[rw]; blk_run_queues(); prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); - io_schedule_timeout(timeout); + ret = io_schedule_timeout(timeout); finish_wait(wqh, &wait); + return ret; } - EXPORT_SYMBOL(blk_congestion_wait); /* @@ -2305,6 +2316,15 @@ mod_page_state(pgpgout, count); else mod_page_state(pgpgin, count); + + if (unlikely(block_dump)) { + char b[BDEVNAME_SIZE]; + printk("%s(%d): %s block %Lu on %s\n", + current->comm, current->pid, + (rw & WRITE) ? "WRITE" : "READ", + (unsigned long long)bio->bi_sector, bdevname(bio->bi_bdev,b)); + } + generic_make_request(bio); return 1; } @@ -2596,6 +2616,12 @@ disk_stat_add(disk, write_ticks, duration); break; case READ: + /* + * schedule the writeout of pending dirty data when the disk is idle. + * (postpone writeback until system is quiescent again.) + */ + if (unlikely(laptop_mode)) + disk_is_spun_up(1); disk_stat_inc(disk, reads); disk_stat_add(disk, read_ticks, duration); break; --- diff/drivers/block/loop.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/block/loop.c 2004-02-09 10:39:52.000000000 +0000 @@ -76,24 +76,34 @@ /* * Transfer functions */ -static int transfer_none(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size, sector_t real_block) +static int transfer_none(struct loop_device *lo, int cmd, + struct page *raw_page, unsigned raw_off, + struct page *loop_page, unsigned loop_off, + int size, sector_t real_block) { - if (raw_buf != loop_buf) { - if (cmd == READ) - memcpy(loop_buf, raw_buf, size); - else - memcpy(raw_buf, loop_buf, size); - } + char *raw_buf = kmap_atomic(raw_page, KM_USER0) + raw_off; + char *loop_buf = kmap_atomic(loop_page, KM_USER1) + loop_off; + + if (cmd == READ) + memcpy(loop_buf, raw_buf, size); + else + memcpy(raw_buf, loop_buf, size); + kunmap_atomic(raw_buf, KM_USER0); + kunmap_atomic(loop_buf, KM_USER1); + cond_resched(); return 0; } -static int transfer_xor(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size, sector_t real_block) +static int transfer_xor(struct loop_device *lo, int cmd, + struct page *raw_page, unsigned raw_off, + struct page *loop_page, unsigned loop_off, + int size, sector_t real_block) { - char *in, *out, *key; - int i, keysize; + char *raw_buf = kmap_atomic(raw_page, KM_USER0) + raw_off; + char *loop_buf = kmap_atomic(loop_page, KM_USER1) + loop_off; + char *in, *out, *key; + int i, keysize; if (cmd == READ) { in = raw_buf; @@ -107,6 +117,10 @@ keysize = lo->lo_encrypt_key_size; for (i = 0; i < size; i++) *out++ = *in++ ^ key[(i & 511) % keysize]; + + kunmap_atomic(raw_buf, KM_USER0); + kunmap_atomic(loop_buf, KM_USER1); + cond_resched(); return 0; } @@ -162,13 +176,15 @@ } static inline int -lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf, - char *lbuf, int size, sector_t rblock) +lo_do_transfer(struct loop_device *lo, int cmd, + struct page *rpage, unsigned roffs, + struct page *lpage, unsigned loffs, + int size, sector_t rblock) { if (!lo->transfer) return 0; - return lo->transfer(lo, cmd, rbuf, lbuf, size, rblock); + return lo->transfer(lo, cmd, rpage, roffs, lpage, loffs, size, rblock); } static int @@ -178,16 +194,15 @@ struct address_space *mapping = file->f_mapping; struct address_space_operations *aops = mapping->a_ops; struct page *page; - char *kaddr, *data; pgoff_t index; - unsigned size, offset; + unsigned size, offset, bv_offs; int len; int ret = 0; down(&mapping->host->i_sem); index = pos >> PAGE_CACHE_SHIFT; offset = pos & ((pgoff_t)PAGE_CACHE_SIZE - 1); - data = kmap(bvec->bv_page) + bvec->bv_offset; + bv_offs = bvec->bv_offset; len = bvec->bv_len; while (len > 0) { sector_t IV; @@ -204,25 +219,28 @@ goto fail; if (aops->prepare_write(file, page, offset, offset+size)) goto unlock; - kaddr = kmap(page); - transfer_result = lo_do_transfer(lo, WRITE, kaddr + offset, - data, size, IV); + transfer_result = lo_do_transfer(lo, WRITE, page, offset, + bvec->bv_page, bv_offs, + size, IV); if (transfer_result) { + char *kaddr; + /* * The transfer failed, but we still write the data to * keep prepare/commit calls balanced. */ printk(KERN_ERR "loop: transfer error block %llu\n", (unsigned long long)index); + kaddr = kmap_atomic(page, KM_USER0); memset(kaddr + offset, 0, size); + kunmap_atomic(kaddr, KM_USER0); } flush_dcache_page(page); - kunmap(page); if (aops->commit_write(file, page, offset, offset+size)) goto unlock; if (transfer_result) goto unlock; - data += size; + bv_offs += size; len -= size; offset = 0; index++; @@ -232,7 +250,6 @@ } up(&mapping->host->i_sem); out: - kunmap(bvec->bv_page); return ret; unlock: @@ -247,12 +264,10 @@ static int lo_send(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos) { - unsigned vecnr; - int ret = 0; - - for (vecnr = 0; vecnr < bio->bi_vcnt; vecnr++) { - struct bio_vec *bvec = &bio->bi_io_vec[vecnr]; + struct bio_vec *bvec; + int i, ret = 0; + bio_for_each_segment(bvec, bio, i) { ret = do_lo_send(lo, bvec, bsize, pos); if (ret < 0) break; @@ -263,7 +278,8 @@ struct lo_read_data { struct loop_device *lo; - char *data; + struct page *page; + unsigned offset; int bsize; }; @@ -271,7 +287,6 @@ lo_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset, unsigned long size) { - char *kaddr; unsigned long count = desc->count; struct lo_read_data *p = (struct lo_read_data*)desc->buf; struct loop_device *lo = p->lo; @@ -282,18 +297,16 @@ if (size > count) size = count; - kaddr = kmap(page); - if (lo_do_transfer(lo, READ, kaddr + offset, p->data, size, IV)) { + if (lo_do_transfer(lo, READ, page, offset, p->page, p->offset, size, IV)) { size = 0; printk(KERN_ERR "loop: transfer error block %ld\n", page->index); desc->error = -EINVAL; } - kunmap(page); desc->count = count - size; desc->written += size; - p->data += size; + p->offset += size; return size; } @@ -306,24 +319,22 @@ int retval; cookie.lo = lo; - cookie.data = kmap(bvec->bv_page) + bvec->bv_offset; + cookie.page = bvec->bv_page; + cookie.offset = bvec->bv_offset; cookie.bsize = bsize; file = lo->lo_backing_file; retval = file->f_op->sendfile(file, &pos, bvec->bv_len, lo_read_actor, &cookie); - kunmap(bvec->bv_page); return (retval < 0)? retval: 0; } static int lo_receive(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos) { - unsigned vecnr; - int ret = 0; - - for (vecnr = 0; vecnr < bio->bi_vcnt; vecnr++) { - struct bio_vec *bvec = &bio->bi_io_vec[vecnr]; + struct bio_vec *bvec; + int i, ret = 0; + bio_for_each_segment(bvec, bio, i) { ret = do_lo_receive(lo, bvec, bsize, pos); if (ret < 0) break; @@ -345,23 +356,6 @@ return ret; } -static int loop_end_io_transfer(struct bio *, unsigned int, int); - -static void loop_put_buffer(struct bio *bio) -{ - /* - * check bi_end_io, may just be a remapped bio - */ - if (bio && bio->bi_end_io == loop_end_io_transfer) { - int i; - - for (i = 0; i < bio->bi_vcnt; i++) - __free_page(bio->bi_io_vec[i].bv_page); - - bio_put(bio); - } -} - /* * Add bio to back of pending list */ @@ -399,129 +393,8 @@ return bio; } -/* - * if this was a WRITE lo->transfer stuff has already been done. for READs, - * queue it for the loop thread and let it do the transfer out of - * bi_end_io context (we don't want to do decrypt of a page with irqs - * disabled) - */ -static int loop_end_io_transfer(struct bio *bio, unsigned int bytes_done, int err) -{ - struct bio *rbh = bio->bi_private; - struct loop_device *lo = rbh->bi_bdev->bd_disk->private_data; - - if (bio->bi_size) - return 1; - - if (err || bio_rw(bio) == WRITE) { - bio_endio(rbh, rbh->bi_size, err); - if (atomic_dec_and_test(&lo->lo_pending)) - up(&lo->lo_bh_mutex); - loop_put_buffer(bio); - } else - loop_add_bio(lo, bio); - - return 0; -} - -static struct bio *loop_copy_bio(struct bio *rbh) -{ - struct bio *bio; - struct bio_vec *bv; - int i; - - bio = bio_alloc(__GFP_NOWARN, rbh->bi_vcnt); - if (!bio) - return NULL; - - /* - * iterate iovec list and alloc pages - */ - __bio_for_each_segment(bv, rbh, i, 0) { - struct bio_vec *bbv = &bio->bi_io_vec[i]; - - bbv->bv_page = alloc_page(__GFP_NOWARN|__GFP_HIGHMEM); - if (bbv->bv_page == NULL) - goto oom; - - bbv->bv_len = bv->bv_len; - bbv->bv_offset = bv->bv_offset; - } - - bio->bi_vcnt = rbh->bi_vcnt; - bio->bi_size = rbh->bi_size; - - return bio; - -oom: - while (--i >= 0) - __free_page(bio->bi_io_vec[i].bv_page); - - bio_put(bio); - return NULL; -} - -static struct bio *loop_get_buffer(struct loop_device *lo, struct bio *rbh) -{ - struct bio *bio; - - /* - * When called on the page reclaim -> writepage path, this code can - * trivially consume all memory. So we drop PF_MEMALLOC to avoid - * stealing all the page reserves and throttle to the writeout rate. - * pdflush will have been woken by page reclaim. Let it do its work. - */ - do { - int flags = current->flags; - - current->flags &= ~PF_MEMALLOC; - bio = loop_copy_bio(rbh); - if (flags & PF_MEMALLOC) - current->flags |= PF_MEMALLOC; - - if (bio == NULL) - blk_congestion_wait(WRITE, HZ/10); - } while (bio == NULL); - - bio->bi_end_io = loop_end_io_transfer; - bio->bi_private = rbh; - bio->bi_sector = rbh->bi_sector + (lo->lo_offset >> 9); - bio->bi_rw = rbh->bi_rw; - bio->bi_bdev = lo->lo_device; - - return bio; -} - -static int loop_transfer_bio(struct loop_device *lo, - struct bio *to_bio, struct bio *from_bio) -{ - sector_t IV; - struct bio_vec *from_bvec, *to_bvec; - char *vto, *vfrom; - int ret = 0, i; - - IV = from_bio->bi_sector + (lo->lo_offset >> 9); - - __bio_for_each_segment(from_bvec, from_bio, i, 0) { - to_bvec = &to_bio->bi_io_vec[i]; - - kmap(from_bvec->bv_page); - kmap(to_bvec->bv_page); - vfrom = page_address(from_bvec->bv_page) + from_bvec->bv_offset; - vto = page_address(to_bvec->bv_page) + to_bvec->bv_offset; - ret |= lo_do_transfer(lo, bio_data_dir(to_bio), vto, vfrom, - from_bvec->bv_len, IV); - kunmap(from_bvec->bv_page); - kunmap(to_bvec->bv_page); - IV += from_bvec->bv_len >> 9; - } - - return ret; -} - static int loop_make_request(request_queue_t *q, struct bio *old_bio) { - struct bio *new_bio = NULL; struct loop_device *lo = q->queuedata; int rw = bio_rw(old_bio); @@ -543,31 +416,11 @@ printk(KERN_ERR "loop: unknown command (%x)\n", rw); goto err; } - - /* - * file backed, queue for loop_thread to handle - */ - if (lo->lo_flags & LO_FLAGS_DO_BMAP) { - loop_add_bio(lo, old_bio); - return 0; - } - - /* - * piggy old buffer on original, and submit for I/O - */ - new_bio = loop_get_buffer(lo, old_bio); - if (rw == WRITE) { - if (loop_transfer_bio(lo, new_bio, old_bio)) - goto err; - } - - generic_make_request(new_bio); + loop_add_bio(lo, old_bio); return 0; - err: if (atomic_dec_and_test(&lo->lo_pending)) up(&lo->lo_bh_mutex); - loop_put_buffer(new_bio); out: bio_io_error(old_bio, old_bio->bi_size); return 0; @@ -580,20 +433,8 @@ { int ret; - /* - * For block backed loop, we know this is a READ - */ - if (lo->lo_flags & LO_FLAGS_DO_BMAP) { - ret = do_bio_filebacked(lo, bio); - bio_endio(bio, bio->bi_size, ret); - } else { - struct bio *rbh = bio->bi_private; - - ret = loop_transfer_bio(lo, bio, rbh); - - bio_endio(rbh, rbh->bi_size, ret); - loop_put_buffer(bio); - } + ret = do_bio_filebacked(lo, bio); + bio_endio(bio, bio->bi_size, ret); } /* @@ -684,31 +525,23 @@ lo_flags |= LO_FLAGS_READ_ONLY; error = -EINVAL; - if (S_ISBLK(inode->i_mode)) { - lo_device = I_BDEV(inode); - if (lo_device == bdev) { - error = -EBUSY; - goto out_putf; - } - lo_blocksize = block_size(lo_device); - if (bdev_read_only(lo_device)) - lo_flags |= LO_FLAGS_READ_ONLY; - } else if (S_ISREG(inode->i_mode)) { + if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) { struct address_space_operations *aops = mapping->a_ops; /* * If we can't read - sorry. If we only can't write - well, * it's going to be read-only. */ - if (!inode->i_fop->sendfile) + if (!lo_file->f_op->sendfile) goto out_putf; if (!aops->prepare_write || !aops->commit_write) lo_flags |= LO_FLAGS_READ_ONLY; lo_blocksize = inode->i_blksize; - lo_flags |= LO_FLAGS_DO_BMAP; - } else + error = 0; + } else { goto out_putf; + } if (!(lo_file->f_mode & FMODE_WRITE)) lo_flags |= LO_FLAGS_READ_ONLY; @@ -738,21 +571,6 @@ blk_queue_make_request(lo->lo_queue, loop_make_request); lo->lo_queue->queuedata = lo; - /* - * we remap to a block device, make sure we correctly stack limits - */ - if (S_ISBLK(inode->i_mode)) { - request_queue_t *q = bdev_get_queue(lo_device); - - blk_queue_max_sectors(lo->lo_queue, q->max_sectors); - blk_queue_max_phys_segments(lo->lo_queue,q->max_phys_segments); - blk_queue_max_hw_segments(lo->lo_queue, q->max_hw_segments); - blk_queue_hardsect_size(lo->lo_queue, queue_hardsect_size(q)); - blk_queue_max_segment_size(lo->lo_queue, q->max_segment_size); - blk_queue_segment_boundary(lo->lo_queue, q->seg_boundary_mask); - blk_queue_merge_bvec(lo->lo_queue, q->merge_bvec_fn); - } - set_blocksize(bdev, lo_blocksize); kernel_thread(loop_thread, lo, CLONE_KERNEL); @@ -1196,7 +1014,6 @@ lo->lo_queue = blk_alloc_queue(GFP_KERNEL); if (!lo->lo_queue) goto out_mem4; - disks[i]->queue = lo->lo_queue; init_MUTEX(&lo->lo_ctl_mutex); init_MUTEX_LOCKED(&lo->lo_sem); init_MUTEX_LOCKED(&lo->lo_bh_mutex); @@ -1209,14 +1026,18 @@ sprintf(disk->devfs_name, "loop/%d", i); disk->private_data = lo; disk->queue = lo->lo_queue; - add_disk(disk); } + + /* We cannot fail after we call this, so another loop!*/ + for (i = 0; i < max_loop; i++) + add_disk(disks[i]); printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop); return 0; out_mem4: while (i--) blk_put_queue(loop_dev[i].lo_queue); + devfs_remove("loop"); i = max_loop; out_mem3: while (i--) --- diff/drivers/block/paride/bpck6.c 2003-06-09 14:18:18.000000000 +0100 +++ source/drivers/block/paride/bpck6.c 2004-02-09 10:39:52.000000000 +0000 @@ -228,7 +228,7 @@ if (p) { memset(p, 0, sizeof(PPC)); - pi->private = (int)p; + pi->private = (unsigned long)p; return 0; } --- diff/drivers/block/paride/frpw.c 2002-11-18 10:11:54.000000000 +0000 +++ source/drivers/block/paride/frpw.c 2004-02-09 10:39:52.000000000 +0000 @@ -261,7 +261,7 @@ frpw_disconnect(pi); if (verbose) { - printk("%s: frpw: port 0x%x, chip %d, mode %d, test=(%d,%d,%d)\n", + printk("%s: frpw: port 0x%x, chip %ld, mode %d, test=(%d,%d,%d)\n", pi->device,pi->port,(pi->private%2),pi->mode,e[0],e[1],r); } --- diff/drivers/block/paride/paride.c 2003-08-20 14:16:27.000000000 +0100 +++ source/drivers/block/paride/paride.c 2004-02-09 10:39:52.000000000 +0000 @@ -102,7 +102,7 @@ #endif -void pi_do_claimed(PIA * pi, void (*cont) (void)) +int pi_schedule_claimed(PIA * pi, void (*cont) (void)) { #ifdef CONFIG_PARPORT unsigned long flags; @@ -111,12 +111,19 @@ if (pi->pardev && parport_claim(pi->pardev)) { pi->claim_cont = cont; spin_unlock_irqrestore(&pi_spinlock, flags); - return; + return 0; } pi->claimed = 1; spin_unlock_irqrestore(&pi_spinlock, flags); #endif - cont(); + return 1; +} +EXPORT_SYMBOL(pi_schedule_claimed); + +void pi_do_claimed(PIA * pi, void (*cont) (void)) +{ + if (pi_schedule_claimed(pi, cont)) + cont(); } EXPORT_SYMBOL(pi_do_claimed); @@ -133,7 +140,7 @@ #endif } -static void pi_unclaim(PIA * pi) +void pi_unclaim(PIA * pi) { pi->claimed = 0; #ifdef CONFIG_PARPORT @@ -142,6 +149,8 @@ #endif } +EXPORT_SYMBOL(pi_unclaim); + void pi_connect(PIA * pi) { pi_claim(pi); --- diff/drivers/block/paride/paride.h 2002-11-18 10:11:54.000000000 +0000 +++ source/drivers/block/paride/paride.h 2004-02-09 10:39:52.000000000 +0000 @@ -45,7 +45,7 @@ int saved_r0; /* saved port state */ int saved_r2; /* saved port state */ int reserved; /* number of ports reserved */ - int private; /* for protocol module */ + unsigned long private; /* for protocol module */ wait_queue_head_t parq; /* semaphore for parport sharing */ void *pardev; /* pointer to pardevice */ @@ -88,11 +88,14 @@ extern void pi_read_block(PIA *pi, char * buf, int count); +extern void pi_unclaim(PIA *pi); + extern void pi_connect(PIA *pi); extern void pi_disconnect(PIA *pi); extern void pi_do_claimed(PIA *pi, void (*cont)(void)); +extern int pi_schedule_claimed(PIA *pi, void (*cont)(void)); /* macros and functions exported to the protocol modules */ --- diff/drivers/block/paride/pd.c 2003-09-17 12:28:04.000000000 +0100 +++ source/drivers/block/paride/pd.c 2004-02-09 10:39:52.000000000 +0000 @@ -138,7 +138,6 @@ static int drive3[8] = { 0, 0, 0, -1, 0, 1, -1, -1 }; static int (*drives[4])[8] = {&drive0, &drive1, &drive2, &drive3}; -static int pd_drive_count; enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV}; @@ -153,6 +152,8 @@ #include #include #include +#include +#include static spinlock_t pd_lock = SPIN_LOCK_UNLOCKED; @@ -188,7 +189,6 @@ MODULE_PARM(drive3, "1-8i"); #include "paride.h" -#include "pseudo.h" #define PD_BITS 4 @@ -235,21 +235,6 @@ #define IDE_IDENTIFY 0xec #define IDE_EJECT 0xed -void pd_setup(char *str, int *ints); -static int pd_open(struct inode *inode, struct file *file); -static void do_pd_request(request_queue_t * q); -static int pd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -static int pd_release(struct inode *inode, struct file *file); -static int pd_revalidate(struct gendisk *p); -static int pd_detect(void); -static void do_pd_read(void); -static void do_pd_read_start(void); -static void do_pd_write(void); -static void do_pd_write_start(void); -static void do_pd_read_drq(void); -static void do_pd_write_done(void); - #define PD_NAMELEN 8 struct pd_unit { @@ -266,153 +251,19 @@ int removable; /* removable media device ? */ int standby; int alt_geom; - int present; char name[PD_NAMELEN]; /* pda, pdb, etc ... */ struct gendisk *gd; }; struct pd_unit pd[PD_UNITS]; -static int pd_identify(struct pd_unit *disk); -static void pd_media_check(struct pd_unit *disk); -static void pd_doorlock(struct pd_unit *disk, int func); -static int pd_check_media(struct gendisk *p); -static void pd_eject(struct pd_unit *disk); - static char pd_scratch[512]; /* scratch block buffer */ -/* the variables below are used mainly in the I/O request engine, which - processes only one request at a time. -*/ - -static struct pd_unit *pd_current; /* current request's drive */ -static int pd_retries = 0; /* i/o error retry count */ -static int pd_busy = 0; /* request being processed ? */ -static struct request *pd_req; /* current request */ -static int pd_block; /* address of next requested block */ -static int pd_count; /* number of blocks still to do */ -static int pd_run; /* sectors in current cluster */ -static int pd_cmd; /* current command READ/WRITE */ -static char *pd_buf; /* buffer for request in progress */ - -static DECLARE_WAIT_QUEUE_HEAD(pd_wait_open); - static char *pd_errs[17] = { "ERR", "INDEX", "ECC", "DRQ", "SEEK", "WRERR", "READY", "BUSY", "AMNF", "TK0NF", "ABRT", "MCR", "IDNF", "MC", "UNC", "???", "TMO" }; -/* kernel glue structures */ - -extern struct block_device_operations pd_fops; - -static struct block_device_operations pd_fops = { - .owner = THIS_MODULE, - .open = pd_open, - .release = pd_release, - .ioctl = pd_ioctl, - .media_changed = pd_check_media, - .revalidate_disk= pd_revalidate -}; - -static void pd_init_units(void) -{ - int unit; - - pd_drive_count = 0; - for (unit = 0; unit < PD_UNITS; unit++) { - int *parm = *drives[unit]; - struct pd_unit *disk = pd + unit; - disk->pi = &disk->pia; - disk->access = 0; - disk->changed = 1; - disk->capacity = 0; - disk->drive = parm[D_SLV]; - disk->present = 0; - snprintf(disk->name, PD_NAMELEN, "%s%c", name, 'a'+unit); - disk->alt_geom = parm[D_GEO]; - disk->standby = parm[D_SBY]; - if (parm[D_PRT]) - pd_drive_count++; - } -} - -static int pd_open(struct inode *inode, struct file *file) -{ - struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; - - disk->access++; - - if (disk->removable) { - pd_media_check(disk); - pd_doorlock(disk, IDE_DOORLOCK); - } - return 0; -} - -static int pd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; - struct hd_geometry *geo = (struct hd_geometry *) arg; - struct hd_geometry g; - - switch (cmd) { - case CDROMEJECT: - if (disk->access == 1) - pd_eject(disk); - return 0; - case HDIO_GETGEO: - if (disk->alt_geom) { - g.heads = PD_LOG_HEADS; - g.sectors = PD_LOG_SECTS; - g.cylinders = disk->capacity / (g.heads * g.sectors); - } else { - g.heads = disk->heads; - g.sectors = disk->sectors; - g.cylinders = disk->cylinders; - } - g.start = get_start_sect(inode->i_bdev); - if (copy_to_user(geo, &g, sizeof(struct hd_geometry))) - return -EFAULT; - return 0; - default: - return -EINVAL; - } -} - -static int pd_release(struct inode *inode, struct file *file) -{ - struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; - - if (!--disk->access && disk->removable) - pd_doorlock(disk, IDE_DOORUNLOCK); - - return 0; -} - -static int pd_check_media(struct gendisk *p) -{ - struct pd_unit *disk = p->private_data; - int r; - if (!disk->removable) - return 0; - pd_media_check(disk); - r = disk->changed; - disk->changed = 0; - return r; -} - -static int pd_revalidate(struct gendisk *p) -{ - struct pd_unit *disk = p->private_data; - if (pd_identify(disk)) - set_capacity(p, disk->capacity); - else - set_capacity(p, 0); - return 0; -} - static inline int status_reg(struct pd_unit *disk) { return pi_read_regr(disk->pi, 1, 6); @@ -453,11 +304,9 @@ static void pd_reset(struct pd_unit *disk) { /* called only for MASTER drive */ - pi_connect(disk->pi); write_status(disk, 4); udelay(50); write_status(disk, 0); - pi_disconnect(disk->pi); udelay(250); } @@ -514,6 +363,236 @@ pd_send_command(disk, count, s, h, c0, c1, func); } +/* The i/o request engine */ + +enum action {Fail = 0, Ok = 1, Hold, Wait}; + +static struct request *pd_req; /* current request */ +static enum action (*phase)(void); + +static void run_fsm(void); + +static void ps_tq_int( void *data); + +static DECLARE_WORK(fsm_tq, ps_tq_int, NULL); + +static void schedule_fsm(void) +{ + if (!nice) + schedule_work(&fsm_tq); + else + schedule_delayed_work(&fsm_tq, nice-1); +} + +static void ps_tq_int(void *data) +{ + run_fsm(); +} + +static enum action do_pd_io_start(void); +static enum action pd_special(void); +static enum action do_pd_read_start(void); +static enum action do_pd_write_start(void); +static enum action do_pd_read_drq(void); +static enum action do_pd_write_done(void); + +static struct request_queue *pd_queue; +static int pd_claimed; + +static struct pd_unit *pd_current; /* current request's drive */ +static PIA *pi_current; /* current request's PIA */ + +static void run_fsm(void) +{ + while (1) { + enum action res; + unsigned long saved_flags; + int stop = 0; + + if (!phase) { + pd_current = pd_req->rq_disk->private_data; + pi_current = pd_current->pi; + phase = do_pd_io_start; + } + + switch (pd_claimed) { + case 0: + pd_claimed = 1; + if (!pi_schedule_claimed(pi_current, run_fsm)) + return; + case 1: + pd_claimed = 2; + pi_current->proto->connect(pi_current); + } + + switch(res = phase()) { + case Ok: case Fail: + pi_disconnect(pi_current); + pd_claimed = 0; + phase = NULL; + spin_lock_irqsave(&pd_lock, saved_flags); + end_request(pd_req, res); + pd_req = elv_next_request(pd_queue); + if (!pd_req) + stop = 1; + spin_unlock_irqrestore(&pd_lock, saved_flags); + if (stop) + return; + case Hold: + schedule_fsm(); + return; + case Wait: + pi_disconnect(pi_current); + pd_claimed = 0; + } + } +} + +static int pd_retries = 0; /* i/o error retry count */ +static int pd_block; /* address of next requested block */ +static int pd_count; /* number of blocks still to do */ +static int pd_run; /* sectors in current cluster */ +static int pd_cmd; /* current command READ/WRITE */ +static char *pd_buf; /* buffer for request in progress */ + +static enum action do_pd_io_start(void) +{ + if (pd_req->flags & REQ_SPECIAL) { + phase = pd_special; + return pd_special(); + } + + pd_cmd = rq_data_dir(pd_req); + if (pd_cmd == READ || pd_cmd == WRITE) { + pd_block = pd_req->sector; + pd_count = pd_req->current_nr_sectors; + if (pd_block + pd_count > get_capacity(pd_req->rq_disk)) + return Fail; + pd_run = pd_req->nr_sectors; + pd_buf = pd_req->buffer; + pd_retries = 0; + if (pd_cmd == READ) + return do_pd_read_start(); + else + return do_pd_write_start(); + } + return Fail; +} + +static enum action pd_special(void) +{ + enum action (*func)(struct pd_unit *) = pd_req->special; + return func(pd_current); +} + +static int pd_next_buf(void) +{ + unsigned long saved_flags; + + pd_count--; + pd_run--; + pd_buf += 512; + pd_block++; + if (!pd_run) + return 1; + if (pd_count) + return 0; + spin_lock_irqsave(&pd_lock, saved_flags); + end_request(pd_req, 1); + pd_count = pd_req->current_nr_sectors; + pd_buf = pd_req->buffer; + spin_unlock_irqrestore(&pd_lock, saved_flags); + return 0; +} + +static unsigned long pd_timeout; + +static enum action do_pd_read_start(void) +{ + if (pd_wait_for(pd_current, STAT_READY, "do_pd_read") & STAT_ERR) { + if (pd_retries < PD_MAX_RETRIES) { + pd_retries++; + return Wait; + } + return Fail; + } + pd_ide_command(pd_current, IDE_READ, pd_block, pd_run); + phase = do_pd_read_drq; + pd_timeout = jiffies + PD_TMO; + return Hold; +} + +static enum action do_pd_write_start(void) +{ + if (pd_wait_for(pd_current, STAT_READY, "do_pd_write") & STAT_ERR) { + if (pd_retries < PD_MAX_RETRIES) { + pd_retries++; + return Wait; + } + return Fail; + } + pd_ide_command(pd_current, IDE_WRITE, pd_block, pd_run); + while (1) { + if (pd_wait_for(pd_current, STAT_DRQ, "do_pd_write_drq") & STAT_ERR) { + if (pd_retries < PD_MAX_RETRIES) { + pd_retries++; + return Wait; + } + return Fail; + } + pi_write_block(pd_current->pi, pd_buf, 512); + if (pd_next_buf()) + break; + } + phase = do_pd_write_done; + pd_timeout = jiffies + PD_TMO; + return Hold; +} + +static inline int pd_ready(void) +{ + return !(status_reg(pd_current) & STAT_BUSY); +} + +static enum action do_pd_read_drq(void) +{ + if (!pd_ready() && !time_after_eq(jiffies, pd_timeout)) + return Hold; + + while (1) { + if (pd_wait_for(pd_current, STAT_DRQ, "do_pd_read_drq") & STAT_ERR) { + if (pd_retries < PD_MAX_RETRIES) { + pd_retries++; + phase = do_pd_read_start; + return Wait; + } + return Fail; + } + pi_read_block(pd_current->pi, pd_buf, 512); + if (pd_next_buf()) + break; + } + return Ok; +} + +static enum action do_pd_write_done(void) +{ + if (!pd_ready() && !time_after_eq(jiffies, pd_timeout)) + return Hold; + + if (pd_wait_for(pd_current, STAT_READY, "do_pd_write_done") & STAT_ERR) { + if (pd_retries < PD_MAX_RETRIES) { + pd_retries++; + phase = do_pd_write_start; + return Wait; + } + return Fail; + } + return Ok; +} + +/* special io requests */ + /* According to the ATA standard, the default CHS geometry should be available following a reset. Some Western Digital drives come up in a mode where only LBA addresses are accepted until the device @@ -522,43 +601,45 @@ static void pd_init_dev_parms(struct pd_unit *disk) { - pi_connect(disk->pi); pd_wait_for(disk, 0, DBMSG("before init_dev_parms")); pd_send_command(disk, disk->sectors, 0, disk->heads - 1, 0, 0, IDE_INIT_DEV_PARMS); udelay(300); pd_wait_for(disk, 0, "Initialise device parameters"); - pi_disconnect(disk->pi); } -static void pd_doorlock(struct pd_unit *disk, int func) +static enum action pd_door_lock(struct pd_unit *disk) +{ + if (!(pd_wait_for(disk, STAT_READY, "Lock") & STAT_ERR)) { + pd_send_command(disk, 1, 0, 0, 0, 0, IDE_DOORLOCK); + pd_wait_for(disk, STAT_READY, "Lock done"); + } + return Ok; +} + +static enum action pd_door_unlock(struct pd_unit *disk) { - pi_connect(disk->pi); if (!(pd_wait_for(disk, STAT_READY, "Lock") & STAT_ERR)) { - pd_send_command(disk, 1, 0, 0, 0, 0, func); + pd_send_command(disk, 1, 0, 0, 0, 0, IDE_DOORUNLOCK); pd_wait_for(disk, STAT_READY, "Lock done"); } - pi_disconnect(disk->pi); + return Ok; } -static void pd_eject(struct pd_unit *disk) +static enum action pd_eject(struct pd_unit *disk) { - pi_connect(disk->pi); pd_wait_for(disk, 0, DBMSG("before unlock on eject")); pd_send_command(disk, 1, 0, 0, 0, 0, IDE_DOORUNLOCK); pd_wait_for(disk, 0, DBMSG("after unlock on eject")); pd_wait_for(disk, 0, DBMSG("before eject")); pd_send_command(disk, 0, 0, 0, 0, 0, IDE_EJECT); pd_wait_for(disk, 0, DBMSG("after eject")); - pi_disconnect(disk->pi); + return Ok; } -static void pd_media_check(struct pd_unit *disk) +static enum action pd_media_check(struct pd_unit *disk) { - int r; - - pi_connect(disk->pi); - r = pd_wait_for(disk, STAT_READY, DBMSG("before media_check")); + int r = pd_wait_for(disk, STAT_READY, DBMSG("before media_check")); if (!(r & STAT_ERR)) { pd_send_command(disk, 1, 1, 0, 0, 0, IDE_READ_VRFY); r = pd_wait_for(disk, STAT_READY, DBMSG("RDY after READ_VRFY")); @@ -571,20 +652,17 @@ pd_send_command(disk, 1, 1, 0, 0, 0, IDE_READ_VRFY); r = pd_wait_for(disk, STAT_READY, DBMSG("RDY after VRFY")); } - pi_disconnect(disk->pi); - + return Ok; } static void pd_standby_off(struct pd_unit *disk) { - pi_connect(disk->pi); pd_wait_for(disk, 0, DBMSG("before STANDBY")); pd_send_command(disk, 0, 0, 0, 0, 0, IDE_STANDBY); pd_wait_for(disk, 0, DBMSG("after STANDBY")); - pi_disconnect(disk->pi); } -static int pd_identify(struct pd_unit *disk) +static enum action pd_identify(struct pd_unit *disk) { int j; char id[PD_ID_LEN + 1]; @@ -598,17 +676,13 @@ if (disk->drive == 0) pd_reset(disk); - pi_connect(disk->pi); write_reg(disk, 6, DRIVE(disk)); pd_wait_for(disk, 0, DBMSG("before IDENT")); pd_send_command(disk, 1, 0, 0, 0, 0, IDE_IDENTIFY); - if (pd_wait_for(disk, STAT_DRQ, DBMSG("IDENT DRQ")) & STAT_ERR) { - pi_disconnect(disk->pi); - return 0; - } + if (pd_wait_for(disk, STAT_DRQ, DBMSG("IDENT DRQ")) & STAT_ERR) + return Fail; pi_read_block(disk->pi, pd_scratch, 512); - pi_disconnect(disk->pi); disk->can_lba = pd_scratch[99] & 2; disk->sectors = le16_to_cpu(*(u16 *) (pd_scratch + 12)); disk->heads = le16_to_cpu(*(u16 *) (pd_scratch + 6)); @@ -640,250 +714,209 @@ if (!disk->standby) pd_standby_off(disk); - return 1; -} - -static int pd_probe_drive(struct pd_unit *disk) -{ - if (disk->drive == -1) { - for (disk->drive = 0; disk->drive <= 1; disk->drive++) - if (pd_identify(disk)) - return 1; - return 0; - } - return pd_identify(disk); + return Ok; } -static struct request_queue *pd_queue; +/* end of io request engine */ -static int pd_detect(void) +static void do_pd_request(request_queue_t * q) { - int k, unit; - struct pd_unit *disk; - - k = 0; - if (pd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */ - disk = pd; - if (pi_init(disk->pi, 1, -1, -1, -1, -1, -1, pd_scratch, - PI_PD, verbose, disk->name)) { - if (pd_probe_drive(disk)) { - disk->present = 1; - k = 1; - } else - pi_release(disk->pi); - } + if (pd_req) + return; + pd_req = elv_next_request(q); + if (!pd_req) + return; - } else { - for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) { - int *parm = *drives[unit]; - if (!parm[D_PRT]) - continue; - if (pi_init(disk->pi, 0, parm[D_PRT], parm[D_MOD], - parm[D_UNI], parm[D_PRO], parm[D_DLY], - pd_scratch, PI_PD, verbose, disk->name)) { - if (pd_probe_drive(disk)) { - disk->present = 1; - k = unit + 1; - } else - pi_release(disk->pi); - } - } - } - for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) { - if (disk->present) { - struct gendisk *p = alloc_disk(1 << PD_BITS); - if (!p) { - disk->present = 0; - k--; - continue; - } - strcpy(p->disk_name, disk->name); - p->fops = &pd_fops; - p->major = major; - p->first_minor = unit << PD_BITS; - set_capacity(p, disk->capacity); - disk->gd = p; - p->private_data = disk; - p->queue = pd_queue; - add_disk(p); - } - } - if (k) - return 1; - printk("%s: no valid drive found\n", name); - return 0; + schedule_fsm(); } -/* The i/o request engine */ - -static int pd_ready(void) +static int pd_special_command(struct pd_unit *disk, + enum action (*func)(struct pd_unit *disk)) { - return !(status_reg(pd_current) & STAT_BUSY); + DECLARE_COMPLETION(wait); + struct request rq; + int err = 0; + + memset(&rq, 0, sizeof(rq)); + rq.errors = 0; + rq.rq_status = RQ_ACTIVE; + rq.rq_disk = disk->gd; + rq.ref_count = 1; + rq.waiting = &wait; + blk_insert_request(disk->gd->queue, &rq, 0, func, 0); + wait_for_completion(&wait); + rq.waiting = NULL; + if (rq.errors) + err = -EIO; + blk_put_request(&rq); + return err; } -static void do_pd_request(request_queue_t * q) -{ - if (pd_busy) - return; -repeat: - pd_req = elv_next_request(q); - if (!pd_req) - return; +/* kernel glue structures */ - pd_block = pd_req->sector; - pd_run = pd_req->nr_sectors; - pd_count = pd_req->current_nr_sectors; - pd_current = pd_req->rq_disk->private_data; - if (pd_block + pd_count > get_capacity(pd_req->rq_disk)) { - end_request(pd_req, 0); - goto repeat; - } +static int pd_open(struct inode *inode, struct file *file) +{ + struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; - pd_cmd = rq_data_dir(pd_req); - pd_buf = pd_req->buffer; - pd_retries = 0; + disk->access++; - pd_busy = 1; - if (pd_cmd == READ) - pi_do_claimed(pd_current->pi, do_pd_read); - else if (pd_cmd == WRITE) - pi_do_claimed(pd_current->pi, do_pd_write); - else { - pd_busy = 0; - end_request(pd_req, 0); - goto repeat; + if (disk->removable) { + pd_special_command(disk, pd_media_check); + pd_special_command(disk, pd_door_lock); } + return 0; } -static int pd_next_buf(void) +static int pd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - unsigned long saved_flags; + struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; + struct hd_geometry *geo = (struct hd_geometry *) arg; + struct hd_geometry g; - pd_count--; - pd_run--; - pd_buf += 512; - pd_block++; - if (!pd_run) - return 1; - if (pd_count) + switch (cmd) { + case CDROMEJECT: + if (disk->access == 1) + pd_special_command(disk, pd_eject); return 0; - spin_lock_irqsave(&pd_lock, saved_flags); - end_request(pd_req, 1); - pd_count = pd_req->current_nr_sectors; - pd_buf = pd_req->buffer; - spin_unlock_irqrestore(&pd_lock, saved_flags); - return 0; + case HDIO_GETGEO: + if (disk->alt_geom) { + g.heads = PD_LOG_HEADS; + g.sectors = PD_LOG_SECTS; + g.cylinders = disk->capacity / (g.heads * g.sectors); + } else { + g.heads = disk->heads; + g.sectors = disk->sectors; + g.cylinders = disk->cylinders; + } + g.start = get_start_sect(inode->i_bdev); + if (copy_to_user(geo, &g, sizeof(struct hd_geometry))) + return -EFAULT; + return 0; + default: + return -EINVAL; + } } -static inline void next_request(int success) +static int pd_release(struct inode *inode, struct file *file) { - unsigned long saved_flags; + struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; - spin_lock_irqsave(&pd_lock, saved_flags); - end_request(pd_req, success); - pd_busy = 0; - do_pd_request(pd_queue); - spin_unlock_irqrestore(&pd_lock, saved_flags); + if (!--disk->access && disk->removable) + pd_special_command(disk, pd_door_unlock); + + return 0; } -static void do_pd_read(void) +static int pd_check_media(struct gendisk *p) { - ps_set_intr(do_pd_read_start, 0, 0, nice); + struct pd_unit *disk = p->private_data; + int r; + if (!disk->removable) + return 0; + pd_special_command(disk, pd_media_check); + r = disk->changed; + disk->changed = 0; + return r; } -static void do_pd_read_start(void) +static int pd_revalidate(struct gendisk *p) { - pd_busy = 1; - - pi_connect(pd_current->pi); - if (pd_wait_for(pd_current, STAT_READY, "do_pd_read") & STAT_ERR) { - pi_disconnect(pd_current->pi); - if (pd_retries < PD_MAX_RETRIES) { - pd_retries++; - pi_do_claimed(pd_current->pi, do_pd_read_start); - return; - } - next_request(0); - return; - } - pd_ide_command(pd_current, IDE_READ, pd_block, pd_run); - ps_set_intr(do_pd_read_drq, pd_ready, PD_TMO, nice); + struct pd_unit *disk = p->private_data; + if (pd_special_command(disk, pd_identify) == 0) + set_capacity(p, disk->capacity); + else + set_capacity(p, 0); + return 0; } -static void do_pd_read_drq(void) +static struct block_device_operations pd_fops = { + .owner = THIS_MODULE, + .open = pd_open, + .release = pd_release, + .ioctl = pd_ioctl, + .media_changed = pd_check_media, + .revalidate_disk= pd_revalidate +}; + +/* probing */ + +static void pd_probe_drive(struct pd_unit *disk) { - while (1) { - if (pd_wait_for(pd_current, STAT_DRQ, "do_pd_read_drq") & STAT_ERR) { - pi_disconnect(pd_current->pi); - if (pd_retries < PD_MAX_RETRIES) { - pd_retries++; - pi_do_claimed(pd_current->pi, do_pd_read_start); + struct gendisk *p = alloc_disk(1 << PD_BITS); + if (!p) + return; + strcpy(p->disk_name, disk->name); + p->fops = &pd_fops; + p->major = major; + p->first_minor = (disk - pd) << PD_BITS; + disk->gd = p; + p->private_data = disk; + p->queue = pd_queue; + + if (disk->drive == -1) { + for (disk->drive = 0; disk->drive <= 1; disk->drive++) + if (pd_special_command(disk, pd_identify) == 0) return; - } - next_request(0); - return; - } - pi_read_block(pd_current->pi, pd_buf, 512); - if (pd_next_buf()) - break; - } - pi_disconnect(pd_current->pi); - next_request(1); + } else if (pd_special_command(disk, pd_identify) == 0) + return; + disk->gd = NULL; + put_disk(p); } -static void do_pd_write(void) +static int pd_detect(void) { - ps_set_intr(do_pd_write_start, 0, 0, nice); -} + int found = 0, unit, pd_drive_count = 0; + struct pd_unit *disk; -static void do_pd_write_start(void) -{ - pd_busy = 1; + for (unit = 0; unit < PD_UNITS; unit++) { + int *parm = *drives[unit]; + struct pd_unit *disk = pd + unit; + disk->pi = &disk->pia; + disk->access = 0; + disk->changed = 1; + disk->capacity = 0; + disk->drive = parm[D_SLV]; + snprintf(disk->name, PD_NAMELEN, "%s%c", name, 'a'+unit); + disk->alt_geom = parm[D_GEO]; + disk->standby = parm[D_SBY]; + if (parm[D_PRT]) + pd_drive_count++; + } - pi_connect(pd_current->pi); - if (pd_wait_for(pd_current, STAT_READY, "do_pd_write") & STAT_ERR) { - pi_disconnect(pd_current->pi); - if (pd_retries < PD_MAX_RETRIES) { - pd_retries++; - pi_do_claimed(pd_current->pi, do_pd_write_start); - return; + if (pd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */ + disk = pd; + if (pi_init(disk->pi, 1, -1, -1, -1, -1, -1, pd_scratch, + PI_PD, verbose, disk->name)) { + pd_probe_drive(disk); + if (!disk->gd) + pi_release(disk->pi); } - next_request(0); - return; - } - pd_ide_command(pd_current, IDE_WRITE, pd_block, pd_run); - while (1) { - if (pd_wait_for(pd_current, STAT_DRQ, "do_pd_write_drq") & STAT_ERR) { - pi_disconnect(pd_current->pi); - if (pd_retries < PD_MAX_RETRIES) { - pd_retries++; - pi_do_claimed(pd_current->pi, do_pd_write_start); - return; + + } else { + for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) { + int *parm = *drives[unit]; + if (!parm[D_PRT]) + continue; + if (pi_init(disk->pi, 0, parm[D_PRT], parm[D_MOD], + parm[D_UNI], parm[D_PRO], parm[D_DLY], + pd_scratch, PI_PD, verbose, disk->name)) { + pd_probe_drive(disk); + if (!disk->gd) + pi_release(disk->pi); } - next_request(0); - return; } - pi_write_block(pd_current->pi, pd_buf, 512); - if (pd_next_buf()) - break; } - ps_set_intr(do_pd_write_done, pd_ready, PD_TMO, nice); -} - -static void do_pd_write_done(void) -{ - if (pd_wait_for(pd_current, STAT_READY, "do_pd_write_done") & STAT_ERR) { - pi_disconnect(pd_current->pi); - if (pd_retries < PD_MAX_RETRIES) { - pd_retries++; - pi_do_claimed(pd_current->pi, do_pd_write_start); - return; + for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) { + if (disk->gd) { + set_capacity(disk->gd, disk->capacity); + add_disk(disk->gd); + found = 1; } - next_request(0); - return; } - pi_disconnect(pd_current->pi); - next_request(1); + if (!found) + printk("%s: no valid drive found\n", name); + return found; } static int __init pd_init(void) @@ -902,7 +935,6 @@ printk("%s: %s version %s, major %d, cluster %d, nice %d\n", name, name, PD_VERSION, major, cluster, nice); - pd_init_units(); if (!pd_detect()) goto out3; @@ -922,8 +954,8 @@ int unit; unregister_blkdev(major, name); for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) { - if (disk->present) { - struct gendisk *p = disk->gd; + struct gendisk *p = disk->gd; + if (p) { disk->gd = NULL; del_gendisk(p); put_disk(p); --- diff/drivers/block/ps2esdi.c 2003-10-09 09:47:33.000000000 +0100 +++ source/drivers/block/ps2esdi.c 2004-02-09 10:39:52.000000000 +0000 @@ -743,7 +743,7 @@ drive_num = int_ret_code >> 5; switch (int_ret_code & 0xf) { case INT_CMD_COMPLETE: - for (i = ESDI_TIMEOUT; i & !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--); + for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--); if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) { printk("%s: timeout reading status word\n", DEVICE_NAME); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); @@ -879,7 +879,7 @@ break; case INT_CMD_COMPLETE: - for (i = ESDI_TIMEOUT; i & !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--); + for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--); if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) { printk("%s: timeout reading status word\n", DEVICE_NAME); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); --- diff/drivers/block/rd.c 2003-10-09 09:47:16.000000000 +0100 +++ source/drivers/block/rd.c 2004-02-09 10:39:52.000000000 +0000 @@ -1,15 +1,15 @@ /* * ramdisk.c - Multiple RAM disk driver - gzip-loading version - v. 0.8 beta. - * - * (C) Chad Page, Theodore Ts'o, et. al, 1995. + * + * (C) Chad Page, Theodore Ts'o, et. al, 1995. * * This RAM disk is designed to have filesystems created on it and mounted - * just like a regular floppy disk. - * + * just like a regular floppy disk. + * * It also does something suggested by Linus: use the buffer cache as the * RAM disk data. This makes it possible to dynamically allocate the RAM disk - * buffer - with some consequences I have to deal with as I write this. - * + * buffer - with some consequences I have to deal with as I write this. + * * This code is based on the original ramdisk.c, written mostly by * Theodore Ts'o (TYT) in 1991. The code was largely rewritten by * Chad Page to use the buffer cache to store the RAM disk data in @@ -33,7 +33,7 @@ * * Added initrd: Werner Almesberger & Hans Lermen, Feb '96 * - * 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) + * 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) * - Chad Page * * Add support for fs images split across >1 disk, Paul Gortmaker, Mar '98 @@ -60,7 +60,7 @@ #include /* The RAM disk size is now a parameter */ -#define NUM_RAMDISKS 16 /* This cannot be overridden (yet) */ +#define NUM_RAMDISKS 16 /* This cannot be overridden (yet) */ /* Various static variables go here. Most are used only in the RAM disk code. */ @@ -73,7 +73,7 @@ * Parameters for the boot-loading of the RAM disk. These are set by * init/main.c (from arguments to the kernel command line) or from the * architecture-specific setup routine (from the stored boot sector - * information). + * information). */ int rd_size = CONFIG_BLK_DEV_RAM_SIZE; /* Size of the RAM disks */ /* @@ -94,7 +94,7 @@ * 2000 Transmeta Corp. * aops copied from ramfs. */ -static int ramdisk_readpage(struct file *file, struct page * page) +static int ramdisk_readpage(struct file *file, struct page *page) { if (!PageUptodate(page)) { void *kaddr = kmap_atomic(page, KM_USER0); @@ -108,7 +108,8 @@ return 0; } -static int ramdisk_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) +static int ramdisk_prepare_write(struct file *file, struct page *page, + unsigned offset, unsigned to) { if (!PageUptodate(page)) { void *kaddr = kmap_atomic(page, KM_USER0); @@ -122,7 +123,8 @@ return 0; } -static int ramdisk_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) +static int ramdisk_commit_write(struct file *file, struct page *page, + unsigned offset, unsigned to) { return 0; } @@ -212,7 +214,7 @@ * 19-JAN-1998 Richard Gooch Added devfs support * */ -static int rd_make_request(request_queue_t * q, struct bio *bio) +static int rd_make_request(request_queue_t *q, struct bio *bio) { struct block_device *bdev = bio->bi_bdev; struct address_space * mapping = bdev->bd_inode->i_mapping; @@ -242,7 +244,8 @@ return 0; } -static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static int rd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { int error; struct block_device *bdev = inode->i_bdev; @@ -250,9 +253,11 @@ if (cmd != BLKFLSBUF) return -EINVAL; - /* special: we want to release the ramdisk memory, - it's not like with the other blockdevices where - this ioctl only flushes away the buffer cache. */ + /* + * special: we want to release the ramdisk memory, it's not like with + * the other blockdevices where this ioctl only flushes away the buffer + * cache + */ error = -EBUSY; down(&bdev->bd_sem); if (bdev->bd_openers <= 2) { @@ -268,7 +273,7 @@ .memory_backed = 1, /* Does not contribute to dirty memory */ }; -static int rd_open(struct inode * inode, struct file * filp) +static int rd_open(struct inode *inode, struct file *filp) { unsigned unit = iminor(inode); @@ -295,12 +300,14 @@ .ioctl = rd_ioctl, }; -/* Before freeing the module, invalidate all of the protected buffers! */ -static void __exit rd_cleanup (void) +/* + * Before freeing the module, invalidate all of the protected buffers! + */ +static void __exit rd_cleanup(void) { int i; - for (i = 0 ; i < NUM_RAMDISKS; i++) { + for (i = 0; i < NUM_RAMDISKS; i++) { struct block_device *bdev = rd_bdev[i]; rd_bdev[i] = NULL; if (bdev) { @@ -311,17 +318,19 @@ put_disk(rd_disks[i]); } devfs_remove("rd"); - unregister_blkdev(RAMDISK_MAJOR, "ramdisk" ); + unregister_blkdev(RAMDISK_MAJOR, "ramdisk"); } -/* This is the registration and initialization section of the RAM disk driver */ -static int __init rd_init (void) +/* + * This is the registration and initialization section of the RAM disk driver + */ +static int __init rd_init(void) { int i; int err = -ENOMEM; if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 || - (rd_blocksize & (rd_blocksize-1))) { + (rd_blocksize & (rd_blocksize-1))) { printk("RAMDISK: wrong blocksize %d, reverting to defaults\n", rd_blocksize); rd_blocksize = BLOCK_SIZE; @@ -362,8 +371,8 @@ /* rd_size is given in kB */ printk("RAMDISK driver initialized: " - "%d RAM disks of %dK size %d blocksize\n", - NUM_RAMDISKS, rd_size, rd_blocksize); + "%d RAM disks of %dK size %d blocksize\n", + NUM_RAMDISKS, rd_size, rd_blocksize); return 0; out_queue: --- diff/drivers/block/scsi_ioctl.c 2003-12-19 09:51:11.000000000 +0000 +++ source/drivers/block/scsi_ioctl.c 2004-02-09 10:39:52.000000000 +0000 @@ -46,14 +46,14 @@ #define SCSI_SENSE_BUFFERSIZE 64 #endif -static int blk_do_rq(request_queue_t *q, struct block_device *bdev, +static int blk_do_rq(request_queue_t *q, struct gendisk *bd_disk, struct request *rq) { char sense[SCSI_SENSE_BUFFERSIZE]; DECLARE_COMPLETION(wait); int err = 0; - rq->rq_disk = bdev->bd_disk; + rq->rq_disk = bd_disk; /* * we need an extra reference to the request, so we can look at @@ -142,7 +142,7 @@ return put_user(1, p); } -static int sg_io(request_queue_t *q, struct block_device *bdev, +static int sg_io(request_queue_t *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr) { unsigned long start_time; @@ -190,7 +190,7 @@ * first try to map it into a bio. reading from device will * be a write to vm. */ - bio = bio_map_user(bdev, (unsigned long) hdr->dxferp, + bio = bio_map_user(q, NULL, (unsigned long) hdr->dxferp, hdr->dxfer_len, reading); /* @@ -246,7 +246,7 @@ * (if he doesn't check that is his problem). * N.B. a non-zero SCSI status is _not_ necessarily an error. */ - blk_do_rq(q, bdev, rq); + blk_do_rq(q, bd_disk, rq); if (bio) bio_unmap_user(bio, reading); @@ -296,7 +296,7 @@ #define READ_DEFECT_DATA_TIMEOUT (60 * HZ ) #define OMAX_SB_LEN 16 /* For backward compatibility */ -static int sg_scsi_ioctl(request_queue_t *q, struct block_device *bdev, +static int sg_scsi_ioctl(request_queue_t *q, struct gendisk *bd_disk, Scsi_Ioctl_Command *sic) { struct request *rq; @@ -312,7 +312,7 @@ return -EFAULT; if (in_len > PAGE_SIZE || out_len > PAGE_SIZE) return -EINVAL; - if (get_user(opcode, sic->data)) + if (get_user(opcode, (int *)sic->data)) return -EFAULT; bytes = max(in_len, out_len); @@ -369,7 +369,7 @@ rq->data_len = bytes; rq->flags |= REQ_BLOCK_PC; - blk_do_rq(q, bdev, rq); + blk_do_rq(q, bd_disk, rq); err = rq->errors & 0xff; /* only 8 bit SCSI status */ if (err) { if (rq->sense_len && rq->sense) { @@ -389,13 +389,13 @@ return err; } -int scsi_cmd_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg) +int scsi_cmd_ioctl(struct gendisk *bd_disk, unsigned int cmd, unsigned long arg) { request_queue_t *q; struct request *rq; int close = 0, err; - q = bdev_get_queue(bdev); + q = bd_disk->queue; if (!q) return -ENXIO; @@ -446,7 +446,7 @@ old_cdb = hdr.cmdp; hdr.cmdp = cdb; - err = sg_io(q, bdev, &hdr); + err = sg_io(q, bd_disk, &hdr); hdr.cmdp = old_cdb; if (copy_to_user((struct sg_io_hdr *) arg, &hdr, sizeof(hdr))) @@ -493,7 +493,7 @@ hdr.timeout = cgc.timeout; hdr.cmdp = cgc.cmd; hdr.cmd_len = sizeof(cgc.cmd); - err = sg_io(q, bdev, &hdr); + err = sg_io(q, bd_disk, &hdr); if (hdr.status) err = -EIO; @@ -514,7 +514,8 @@ if (!arg) break; - err = sg_scsi_ioctl(q, bdev, (Scsi_Ioctl_Command *)arg); + err = sg_scsi_ioctl(q, bd_disk, + (Scsi_Ioctl_Command *)arg); break; case CDROMCLOSETRAY: close = 1; @@ -528,7 +529,7 @@ rq->cmd[0] = GPCMD_START_STOP_UNIT; rq->cmd[4] = 0x02 + (close != 0); rq->cmd_len = 6; - err = blk_do_rq(q, bdev, rq); + err = blk_do_rq(q, bd_disk, rq); blk_put_request(rq); break; default: --- diff/drivers/block/swim3.c 2003-08-20 14:16:27.000000000 +0100 +++ source/drivers/block/swim3.c 2004-02-09 10:39:52.000000000 +0000 @@ -24,7 +24,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -144,7 +147,7 @@ #define RELAX 3 /* also eject in progress */ #define READ_DATA_0 4 #define TWOMEG_DRIVE 5 -#define SINGLE_SIDED 6 +#define SINGLE_SIDED 6 /* drive or diskette is 4MB type? */ #define DRIVE_PRESENT 7 #define DISK_IN 8 #define WRITE_PROT 9 @@ -184,6 +187,7 @@ int req_sector; /* sector number ditto */ int scount; /* # sectors we're transferring at present */ int retries; + int settle_time; int secpercyl; /* disk geometry information */ int secpertrack; int total_secs; @@ -232,8 +236,9 @@ static void act(struct floppy_state *fs); static void scan_timeout(unsigned long data); static void seek_timeout(unsigned long data); +static void settle_timeout(unsigned long data); static void xfer_timeout(unsigned long data); -static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs); /*static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);*/ static int grab_drive(struct floppy_state *fs, enum swim_state state, int interruptible); @@ -274,7 +279,6 @@ udelay(2); out_8(&sw->select, sw->select & ~LSTRB); udelay(1); - out_8(&sw->select, RELAX); } static int swim3_readbit(struct floppy_state *fs, int bit) @@ -283,9 +287,8 @@ int stat; swim3_select(fs, bit); - udelay(10); + udelay(1); stat = in_8(&sw->status); - out_8(&sw->select, RELAX); return (stat & DATA) == 0; } @@ -374,13 +377,13 @@ static inline void scan_track(struct floppy_state *fs) { volatile struct swim3 *sw = fs->swim3; - int xx; swim3_select(fs, READ_DATA_0); - xx = sw->intr; /* clear SEEN_SECTOR bit */ + in_8(&sw->intr); /* clear SEEN_SECTOR bit */ + in_8(&sw->error); + out_8(&sw->intr_enable, SEEN_SECTOR); out_8(&sw->control_bis, DO_ACTION); /* enable intr when track found */ - out_8(&sw->intr_enable, ERROR_INTR | SEEN_SECTOR); set_timeout(fs, HZ, scan_timeout); /* enable timeout */ } @@ -395,12 +398,14 @@ swim3_action(fs, SEEK_NEGATIVE); sw->nseek = -n; } - fs->expect_cyl = (fs->cur_cyl > 0)? fs->cur_cyl + n: -1; + fs->expect_cyl = (fs->cur_cyl >= 0)? fs->cur_cyl + n: -1; swim3_select(fs, STEP); - out_8(&sw->control_bis, DO_SEEK); + in_8(&sw->error); /* enable intr when seek finished */ - out_8(&sw->intr_enable, ERROR_INTR | SEEK_DONE); - set_timeout(fs, HZ/2, seek_timeout); /* enable timeout */ + out_8(&sw->intr_enable, SEEK_DONE); + out_8(&sw->control_bis, DO_SEEK); + set_timeout(fs, 3*HZ, seek_timeout); /* enable timeout */ + fs->settle_time = 0; } static inline void init_dma(struct dbdma_cmd *cp, int cmd, @@ -448,18 +453,21 @@ } ++cp; out_le16(&cp->command, DBDMA_STOP); + out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS); + in_8(&sw->error); + out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS); + if (rq_data_dir(fd_req) == WRITE) + out_8(&sw->control_bis, WRITE_SECTORS); + in_8(&sw->intr); out_le32(&dr->control, (RUN << 16) | RUN); - out_8(&sw->control_bis, - (rq_data_dir(fd_req) == WRITE? WRITE_SECTORS: 0) | DO_ACTION); /* enable intr when transfer complete */ - out_8(&sw->intr_enable, ERROR_INTR | TRANSFER_DONE); + out_8(&sw->intr_enable, TRANSFER_DONE); + out_8(&sw->control_bis, DO_ACTION); set_timeout(fs, 2*HZ, xfer_timeout); /* enable timeout */ } static void act(struct floppy_state *fs) { - volatile struct swim3 *sw = fs->swim3; - for (;;) { switch (fs->state) { case idle: @@ -492,20 +500,10 @@ return; case settling: - /* wait for SEEK_COMPLETE to become true */ - swim3_select(fs, SEEK_COMPLETE); - udelay(10); - out_8(&sw->intr_enable, ERROR_INTR | DATA_CHANGED); - in_8(&sw->intr); /* clear DATA_CHANGED */ - if (in_8(&sw->status) & DATA) { - /* seek_complete is not yet true */ - set_timeout(fs, HZ/2, seek_timeout); - return; - } - out_8(&sw->intr_enable, 0); - in_8(&sw->intr); - fs->state = locating; - break; + /* check for SEEK_COMPLETE after 30ms */ + fs->settle_time = (HZ + 32) / 33; + set_timeout(fs, fs->settle_time, settle_timeout); + return; case do_transfer: if (fs->cur_cyl != fs->req_cyl) { @@ -537,7 +535,7 @@ volatile struct swim3 *sw = fs->swim3; fs->timeout_pending = 0; - out_8(&sw->control_bic, DO_ACTION); + out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS); out_8(&sw->select, RELAX); out_8(&sw->intr_enable, 0); fs->cur_cyl = -1; @@ -557,20 +555,34 @@ volatile struct swim3 *sw = fs->swim3; fs->timeout_pending = 0; - if (fs->state == settling) { - printk(KERN_ERR "swim3: MSI sel=%x ctrl=%x stat=%x intr=%x ie=%x\n", - sw->select, sw->control, sw->status, sw->intr, sw->intr_enable); - } out_8(&sw->control_bic, DO_SEEK); out_8(&sw->select, RELAX); out_8(&sw->intr_enable, 0); - if (fs->state == settling && swim3_readbit(fs, SEEK_COMPLETE)) { - /* printk(KERN_DEBUG "swim3: missed settling interrupt\n"); */ + printk(KERN_ERR "swim3: seek timeout\n"); + end_request(fd_req, 0); + fs->state = idle; + start_request(fs); +} + +static void settle_timeout(unsigned long data) +{ + struct floppy_state *fs = (struct floppy_state *) data; + volatile struct swim3 *sw = fs->swim3; + + fs->timeout_pending = 0; + if (swim3_readbit(fs, SEEK_COMPLETE)) { + out_8(&sw->select, RELAX); fs->state = locating; act(fs); return; } - printk(KERN_ERR "swim3: seek timeout\n"); + out_8(&sw->select, RELAX); + if (fs->settle_time < 2*HZ) { + ++fs->settle_time; + set_timeout(fs, 1, settle_timeout); + return; + } + printk(KERN_ERR "swim3: seek settle timeout\n"); end_request(fd_req, 0); fs->state = idle; start_request(fs); @@ -583,9 +595,13 @@ struct dbdma_regs *dr = fs->dma; struct dbdma_cmd *cp = fs->dma_cmd; unsigned long s; + int n; fs->timeout_pending = 0; st_le32(&dr->control, RUN << 16); + /* We must wait a bit for dbdma to stop */ + for (n = 0; (in_le32(&dr->status) & ACTIVE) && n < 1000; n++) + udelay(1); out_8(&sw->intr_enable, 0); out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION); out_8(&sw->select, RELAX); @@ -604,7 +620,7 @@ start_request(fs); } -static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct floppy_state *fs = (struct floppy_state *) dev_id; volatile struct swim3 *sw = fs->swim3; @@ -613,18 +629,15 @@ struct dbdma_regs *dr; struct dbdma_cmd *cp; - err = in_8(&sw->error); intr = in_8(&sw->intr); -#if 0 - printk("swim3 intr state=%d intr=%x err=%x\n", fs->state, intr, err); -#endif + err = (intr & ERROR_INTR)? in_8(&sw->error): 0; if ((intr & ERROR_INTR) && fs->state != do_transfer) printk(KERN_ERR "swim3_interrupt, state=%d, dir=%lx, intr=%x, err=%x\n", fs->state, rq_data_dir(fd_req), intr, err); switch (fs->state) { case locating: if (intr & SEEN_SECTOR) { - out_8(&sw->control_bic, DO_ACTION); + out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS); out_8(&sw->select, RELAX); out_8(&sw->intr_enable, 0); del_timer(&fs->timeout); @@ -674,19 +687,33 @@ case do_transfer: if ((intr & (ERROR_INTR | TRANSFER_DONE)) == 0) break; - dr = fs->dma; - cp = fs->dma_cmd; - /* We must wait a bit for dbdma to complete */ - for (n=0; (in_le32(&dr->status) & ACTIVE) && n < 1000; n++) - udelay(10); - DBDMA_DO_STOP(dr); out_8(&sw->intr_enable, 0); out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION); out_8(&sw->select, RELAX); del_timer(&fs->timeout); fs->timeout_pending = 0; + dr = fs->dma; + cp = fs->dma_cmd; if (rq_data_dir(fd_req) == WRITE) ++cp; + /* + * Check that the main data transfer has finished. + * On writing, the swim3 sometimes doesn't use + * up all the bytes of the postamble, so we can still + * see DMA active here. That doesn't matter as long + * as all the sector data has been transferred. + */ + if ((intr & ERROR_INTR) == 0 && cp->xfer_status == 0) { + /* wait a little while for DMA to complete */ + for (n = 0; n < 100; ++n) { + if (cp->xfer_status != 0) + break; + udelay(1); + barrier(); + } + } + /* turn off DMA */ + out_le32(&dr->control, (RUN | PAUSE) << 16); stat = ld_le16(&cp->xfer_status); resid = ld_le16(&cp->res_count); if (intr & ERROR_INTR) { @@ -742,6 +769,7 @@ default: printk(KERN_ERR "swim3: don't know what to do in state %d\n", fs->state); } + return IRQ_HANDLED; } /* @@ -793,16 +821,19 @@ if (err) return err; swim3_action(fs, EJECT); - for (n = 2*HZ; n > 0; --n) { - if (swim3_readbit(fs, RELAX)) - break; + for (n = 20; n > 0; --n) { if (signal_pending(current)) { err = -EINTR; break; } + swim3_select(fs, RELAX); current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); + if (swim3_readbit(fs, DISK_IN) == 0) + break; } + swim3_select(fs, RELAX); + udelay(150); fs->ejected = 1; release_drive(fs); return err; @@ -847,29 +878,31 @@ if (fs->ref_count == 0) { if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) return -ENXIO; - out_8(&sw->mode, 0x95); - out_8(&sw->control_bic, 0xff); out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2); + out_8(&sw->control_bic, 0xff); + out_8(&sw->mode, 0x95); udelay(10); out_8(&sw->intr_enable, 0); out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE); swim3_action(fs, MOTOR_ON); fs->write_prot = -1; fs->cur_cyl = -1; - for (n = HZ; n > 0; --n) { - if (swim3_readbit(fs, SEEK_COMPLETE)) + for (n = 0; n < 2 * HZ; ++n) { + if (n >= HZ/30 && swim3_readbit(fs, SEEK_COMPLETE)) break; if (signal_pending(current)) { err = -EINTR; break; } + swim3_select(fs, RELAX); current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); } if (err == 0 && (swim3_readbit(fs, SEEK_COMPLETE) == 0 || swim3_readbit(fs, DISK_IN) == 0)) err = -ENXIO; - swim3_action(fs, 9); + swim3_action(fs, SETMFM); + swim3_select(fs, RELAX); } else if (fs->ref_count == -1 || filp->f_flags & O_EXCL) return -EBUSY; @@ -892,6 +925,7 @@ if (fs->ref_count == 0) { swim3_action(fs, MOTOR_OFF); out_8(&sw->control_bic, DRIVE_ENABLE | INTR_ENABLE); + swim3_select(fs, RELAX); } return err; } @@ -911,6 +945,7 @@ if (fs->ref_count > 0 && --fs->ref_count == 0) { swim3_action(fs, MOTOR_OFF); out_8(&sw->control_bic, 0xff); + swim3_select(fs, RELAX); } return 0; } @@ -933,15 +968,17 @@ sw = fs->swim3; grab_drive(fs, revalidating, 0); out_8(&sw->intr_enable, 0); - out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE); - swim3_action(fs, MOTOR_ON); + out_8(&sw->control_bis, DRIVE_ENABLE); + swim3_action(fs, MOTOR_ON); /* necessary? */ fs->write_prot = -1; fs->cur_cyl = -1; + mdelay(1); for (n = HZ; n > 0; --n) { if (swim3_readbit(fs, SEEK_COMPLETE)) break; if (signal_pending(current)) break; + swim3_select(fs, RELAX); current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); } @@ -951,17 +988,14 @@ swim3_action(fs, MOTOR_OFF); else { fs->ejected = 0; - swim3_action(fs, 9); + swim3_action(fs, SETMFM); } + swim3_select(fs, RELAX); release_drive(fs); return ret; } -static void floppy_off(unsigned int nr) -{ -} - static struct block_device_operations floppy_fops = { .open = floppy_open, .release = floppy_release, @@ -1104,3 +1138,5 @@ return 0; } + +module_init(swim3_init) --- diff/drivers/cdrom/cdrom.c 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/cdrom/cdrom.c 2004-02-09 10:39:52.000000000 +0000 @@ -695,6 +695,35 @@ return ret; } +static int mo_open_write(struct cdrom_device_info *cdi) +{ + struct cdrom_generic_command cgc; + char buffer[255]; + int ret; + + init_cdrom_command(&cgc, &buffer, 4, CGC_DATA_READ); + cgc.quiet = 1; + + /* + * obtain write protect information as per + * drivers/scsi/sd.c:sd_read_write_protect_flag + */ + + ret = cdrom_mode_sense(cdi, &cgc, GPMODE_ALL_PAGES, 0); + if (ret) + ret = cdrom_mode_sense(cdi, &cgc, GPMODE_VENDOR_PAGE, 0); + if (ret) { + cgc.buflen = 255; + ret = cdrom_mode_sense(cdi, &cgc, GPMODE_ALL_PAGES, 0); + } + + /* drive gave us no info, let the user go ahead */ + if (ret) + return 0; + + return buffer[3] & 0x80; +} + /* * returns 0 for ok to open write, non-0 to disallow */ @@ -706,11 +735,8 @@ ret = cdrom_mrw_open_write(cdi); else if (CDROM_CAN(CDC_DVD_RAM)) ret = cdrom_dvdram_open_write(cdi); - /* - * needs to really check whether media is writeable - */ else if (CDROM_CAN(CDC_MO_DRIVE)) - ret = 0; + ret = mo_open_write(cdi); return ret; } @@ -1773,7 +1799,7 @@ int ret; /* Try the generic SCSI command ioctl's first.. */ - ret = scsi_cmd_ioctl(ip->i_bdev, cmd, arg); + ret = scsi_cmd_ioctl(ip->i_bdev->bd_disk, cmd, arg); if (ret != -ENOTTY) return ret; @@ -2268,7 +2294,7 @@ return -EINVAL; /* FIXME: we need upper bound checking, too!! */ - if (lba < 0 || ra.nframes <= 0 || ra.nframes > 64) + if (lba < 0 || ra.nframes <= 0 || ra.nframes > CD_FRAMES) return -EINVAL; /* --- diff/drivers/char/Kconfig 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/char/Kconfig 2004-02-09 10:39:52.000000000 +0000 @@ -588,30 +588,6 @@ bool "Support for console on line printer" depends on PC9800_OLDLP - -menu "Mice" - -config BUSMOUSE - tristate "Bus Mouse Support" - ---help--- - Say Y here if your machine has a bus mouse as opposed to a serial - mouse. Most people have a regular serial MouseSystem or - Microsoft mouse (made by Logitech) that plugs into a COM port - (rectangular with 9 or 25 pins). These people say N here. - - If you have a laptop, you either have to check the documentation or - experiment a bit to find out whether the trackball is a serial mouse - or not; it's best to say Y here for you. - - This is the generic bus mouse driver code. If you have a bus mouse, - you will have to say Y here and also to the specific driver for your - mouse below. - - To compile this driver as a module, choose M here: the - module will be called busmouse. - -endmenu - config QIC02_TAPE tristate "QIC-02 tape support" help @@ -794,8 +770,7 @@ precision in some cases. To compile this driver as a module, choose M here: the - module will be called genrtc. To load the module automatically - add 'alias char-major-10-135 genrtc' to your /etc/modules.conf + module will be called genrtc. config GEN_RTC_X bool "Extended RTC operation" @@ -962,12 +937,16 @@ If compiled as a module, it will be called scx200_gpio. config RAW_DRIVER - tristate "RAW driver (/dev/raw/rawN)" + tristate "RAW driver (/dev/raw/rawN) (OBSOLETE)" help The raw driver permits block devices to be bound to /dev/raw/rawN. Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. See the raw(8) manpage for more details. + The raw driver is deprecated and may be removed from 2.7 + kernels. Applications should simply open the device (eg /dev/hda1) + with the O_DIRECT flag. + config MAX_RAW_DEVS int "Maximum number of RAW devices to support (1-8192)" depends on RAW_DRIVER --- diff/drivers/char/Makefile 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/char/Makefile 2004-02-09 10:39:52.000000000 +0000 @@ -49,7 +49,6 @@ obj-$(CONFIG_TIPAR) += tipar.o obj-$(CONFIG_PC9800_OLDLP) += lp_old98.o -obj-$(CONFIG_BUSMOUSE) += busmouse.o obj-$(CONFIG_DTLK) += dtlk.o obj-$(CONFIG_R3964) += n_r3964.o obj-$(CONFIG_APPLICOM) += applicom.o @@ -57,7 +56,9 @@ obj-$(CONFIG_RTC) += rtc.o obj-$(CONFIG_GEN_RTC) += genrtc.o obj-$(CONFIG_EFI_RTC) += efirtc.o -ifeq ($(CONFIG_PPC),) +ifeq ($(CONFIG_GENERIC_NVRAM),y) + obj-$(CONFIG_NVRAM) += generic_nvram.o +else obj-$(CONFIG_NVRAM) += nvram.o endif obj-$(CONFIG_TOSHIBA) += toshiba.o --- diff/drivers/char/agp/intel-agp.c 2004-01-19 10:22:56.000000000 +0000 +++ source/drivers/char/agp/intel-agp.c 2004-02-09 10:39:52.000000000 +0000 @@ -1432,6 +1432,8 @@ intel_configure(); else if (bridge->driver == &intel_845_driver) intel_845_configure(); + else if (bridge->driver == &intel_830mp_driver) + intel_830mp_configure(); return 0; } --- diff/drivers/char/amiserial.c 2003-10-09 09:47:33.000000000 +0100 +++ source/drivers/char/amiserial.c 2004-02-09 10:39:52.000000000 +0000 @@ -1248,57 +1248,48 @@ } -static int get_modem_info(struct async_struct * info, unsigned int *value) +static int rs_tiocmget(struct tty_struct *tty, struct file *file) { + struct async_struct * info = (struct async_struct *)tty->driver_data; unsigned char control, status; - unsigned int result; unsigned long flags; + if (serial_paranoia_check(info, tty->name, "rs_ioctl")) + return -ENODEV; + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + control = info->MCR; local_irq_save(flags); status = ciab.pra; local_irq_restore(flags); - result = ((control & SER_RTS) ? TIOCM_RTS : 0) + return ((control & SER_RTS) ? TIOCM_RTS : 0) | ((control & SER_DTR) ? TIOCM_DTR : 0) | (!(status & SER_DCD) ? TIOCM_CAR : 0) | (!(status & SER_DSR) ? TIOCM_DSR : 0) | (!(status & SER_CTS) ? TIOCM_CTS : 0); - if (copy_to_user(value, &result, sizeof(int))) - return -EFAULT; - return 0; } -static int set_modem_info(struct async_struct * info, unsigned int cmd, - unsigned int *value) +static int rs_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) { - unsigned int arg; + struct async_struct * info = (struct async_struct *)tty->driver_data; unsigned long flags; - if (copy_from_user(&arg, value, sizeof(int))) - return -EFAULT; + if (serial_paranoia_check(info, tty->name, "rs_ioctl")) + return -ENODEV; + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; - switch (cmd) { - case TIOCMBIS: - if (arg & TIOCM_RTS) - info->MCR |= SER_RTS; - if (arg & TIOCM_DTR) - info->MCR |= SER_DTR; - break; - case TIOCMBIC: - if (arg & TIOCM_RTS) - info->MCR &= ~SER_RTS; - if (arg & TIOCM_DTR) - info->MCR &= ~SER_DTR; - break; - case TIOCMSET: - info->MCR = ((info->MCR & ~(SER_RTS | SER_DTR)) - | ((arg & TIOCM_RTS) ? SER_RTS : 0) - | ((arg & TIOCM_DTR) ? SER_DTR : 0)); - break; - default: - return -EINVAL; - } local_irq_save(flags); + if (set & TIOCM_RTS) + info->MCR |= SER_RTS; + if (set & TIOCM_DTR) + info->MCR |= SER_DTR; + if (clear & TIOCM_RTS) + info->MCR &= ~SER_RTS; + if (clear & TIOCM_DTR) + info->MCR &= ~SER_DTR; rtsdtr_ctrl(info->MCR); local_irq_restore(flags); return 0; @@ -1344,12 +1335,6 @@ } switch (cmd) { - case TIOCMGET: - return get_modem_info(info, (unsigned int *) arg); - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - return set_modem_info(info, cmd, (unsigned int *) arg); case TIOCGSERIAL: return get_serial_info(info, (struct serial_struct *) arg); @@ -2045,6 +2030,8 @@ .send_xchar = rs_send_xchar, .wait_until_sent = rs_wait_until_sent, .read_proc = rs_read_proc, + .tiocmget = rs_tiocmget, + .tiocmset = rs_tiocmset, }; /* --- diff/drivers/char/cyclades.c 2003-10-09 09:47:33.000000000 +0100 +++ source/drivers/char/cyclades.c 2004-02-09 10:39:52.000000000 +0000 @@ -3632,8 +3632,9 @@ } static int -get_modem_info(struct cyclades_port * info, unsigned int *value) +cy_tiocmget(struct tty_struct *tty, struct file *file) { + struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; int card,chip,channel,index; unsigned char *base_addr; unsigned long flags; @@ -3645,6 +3646,9 @@ struct BOARD_CTRL *board_ctrl; struct CH_CTRL *ch_ctrl; + if (serial_paranoia_check(info, tty->name, __FUNCTION__)) + return -ENODEV; + card = info->card; channel = (info->line) - (cy_card[card].first_line); if (!IS_CYC_Z(cy_card[card])) { @@ -3700,24 +3704,27 @@ } } - return cy_put_user(result, value); -} /* get_modem_info */ + return result; +} /* cy_tiomget */ static int -set_modem_info(struct cyclades_port * info, unsigned int cmd, - unsigned int *value) +cy_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) { + struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; int card,chip,channel,index; unsigned char *base_addr; unsigned long flags; - unsigned int arg = cy_get_user((unsigned long *) value); struct FIRM_ID *firm_id; struct ZFW_CTRL *zfw_ctrl; struct BOARD_CTRL *board_ctrl; struct CH_CTRL *ch_ctrl; int retval; + if (serial_paranoia_check(info, tty->name, __FUNCTION__)) + return -ENODEV; + card = info->card; channel = (info->line) - (cy_card[card].first_line); if (!IS_CYC_Z(cy_card[card])) { @@ -3728,66 +3735,7 @@ (cy_card[card].base_addr + (cy_chip_offset[chip]<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR2<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR1<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR2<rtsdtr_inv) { - cy_writeb((u_long)base_addr+(CyMSVR1<rtsdtr_inv) { @@ -3796,7 +3744,8 @@ cy_writeb((u_long)base_addr+(CyMSVR1<rtsdtr_inv) { @@ -3805,8 +3754,8 @@ cy_writeb((u_long)base_addr+(CyMSVR1<rtsdtr_inv) { @@ -3821,7 +3770,8 @@ cy_readb(base_addr+(CyMSVR2<rtsdtr_inv) { @@ -3837,10 +3787,6 @@ cy_readb(base_addr+(CyMSVR2<board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; - switch (cmd) { - case TIOCMBIS: - if (arg & TIOCM_RTS){ - CY_LOCK(info, flags); - cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS); - CY_UNLOCK(info, flags); - } - if (arg & TIOCM_DTR){ - CY_LOCK(info, flags); - cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR); -#ifdef CY_DEBUG_DTR - printk("cyc:set_modem_info raising Z DTR\n"); -#endif - CY_UNLOCK(info, flags); - } - break; - case TIOCMBIC: - if (arg & TIOCM_RTS){ - CY_LOCK(info, flags); - cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_RTS); - CY_UNLOCK(info, flags); - } - if (arg & TIOCM_DTR){ - CY_LOCK(info, flags); - cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR); -#ifdef CY_DEBUG_DTR - printk("cyc:set_modem_info clearing Z DTR\n"); -#endif - CY_UNLOCK(info, flags); - } - break; - case TIOCMSET: - if (arg & TIOCM_RTS){ + if (set & TIOCM_RTS){ CY_LOCK(info, flags); cy_writel(&ch_ctrl[channel].rs_control, cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS); CY_UNLOCK(info, flags); - }else{ + } + if (clear & TIOCM_RTS) { CY_LOCK(info, flags); cy_writel(&ch_ctrl[channel].rs_control, cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_RTS); CY_UNLOCK(info, flags); - } - if (arg & TIOCM_DTR){ + } + if (set & TIOCM_DTR){ CY_LOCK(info, flags); cy_writel(&ch_ctrl[channel].rs_control, cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR); @@ -3909,7 +3820,8 @@ printk("cyc:set_modem_info raising Z DTR\n"); #endif CY_UNLOCK(info, flags); - }else{ + } + if (clear & TIOCM_DTR) { CY_LOCK(info, flags); cy_writel(&ch_ctrl[channel].rs_control, cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR); @@ -3917,10 +3829,6 @@ printk("cyc:set_modem_info clearing Z DTR\n"); #endif CY_UNLOCK(info, flags); - } - break; - default: - return -EINVAL; } }else{ return -ENODEV; @@ -3935,7 +3843,7 @@ CY_UNLOCK(info, flags); } return 0; -} /* set_modem_info */ +} /* cy_tiocmset */ /* * cy_break() --- routine which turns the break handling on or off @@ -4242,14 +4150,6 @@ case CYGETWAIT: ret_val = info->closing_wait / (HZ/100); break; - case TIOCMGET: - ret_val = get_modem_info(info, (unsigned int *) arg); - break; - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - ret_val = set_modem_info(info, cmd, (unsigned int *) arg); - break; case TIOCGSERIAL: ret_val = get_serial_info(info, (struct serial_struct *) arg); break; @@ -5429,6 +5329,8 @@ .break_ctl = cy_break, .wait_until_sent = cy_wait_until_sent, .read_proc = cyclades_get_proc_info, + .tiocmget = cy_tiocmget, + .tiocmset = cy_tiocmset, }; static int __init --- diff/drivers/char/drm/Kconfig 2004-02-09 10:36:10.000000000 +0000 +++ source/drivers/char/drm/Kconfig 2004-02-09 10:39:52.000000000 +0000 @@ -76,7 +76,7 @@ tristate "SiS video cards" depends on DRM && AGP help - Choose this option if you have a SiS 630 or compatibel video + Choose this option if you have a SiS 630 or compatible video chipset. If M is selected the module will be called sis. AGP support is required for this driver to work. --- diff/drivers/char/drm/drm.h 2003-07-22 18:54:27.000000000 +0100 +++ source/drivers/char/drm/drm.h 2004-02-09 10:39:52.000000000 +0000 @@ -580,6 +580,16 @@ unsigned long handle; /**< Used for mapping / unmapping */ } drm_scatter_gather_t; +/** + * DRM_IOCTL_SET_VERSION ioctl argument type. + */ +typedef struct drm_set_version { + int drm_di_major; + int drm_di_minor; + int drm_dd_major; + int drm_dd_minor; +} drm_set_version_t; + #define DRM_IOCTL_BASE 'd' #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) @@ -594,6 +604,7 @@ #define DRM_IOCTL_GET_MAP DRM_IOWR(0x04, drm_map_t) #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, drm_client_t) #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, drm_stats_t) +#define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, drm_set_version_t) #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t) #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t) --- diff/drivers/char/drm/drmP.h 2004-01-19 10:22:56.000000000 +0000 +++ source/drivers/char/drm/drmP.h 2004-02-09 10:39:52.000000000 +0000 @@ -92,8 +92,8 @@ #ifndef __HAVE_DMA #define __HAVE_DMA 0 #endif -#ifndef __HAVE_DMA_IRQ -#define __HAVE_DMA_IRQ 0 +#ifndef __HAVE_IRQ +#define __HAVE_IRQ 0 #endif #ifndef __HAVE_DMA_WAITLIST #define __HAVE_DMA_WAITLIST 0 @@ -324,6 +324,7 @@ #define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x)) #define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist) +#define DRM_IF_VERSION(maj, min) ((maj) << 16 | (min)) /** * Get the private SAREA mapping. * @@ -362,10 +363,13 @@ typedef int drm_ioctl_t( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); -typedef struct drm_pci_list { - u16 vendor; - u16 device; -} drm_pci_list_t; +typedef struct drm_pci_id_list +{ + int vendor; + int device; + long driver_private; + char *name; +} drm_pci_id_list_t; typedef struct drm_ioctl_desc { drm_ioctl_t *func; @@ -488,6 +492,9 @@ struct drm_device *dev; int remove_auth_on_close; unsigned long lock_count; +#ifdef DRIVER_FILE_FIELDS + DRIVER_FILE_FIELDS; +#endif } drm_file_t; /** Wait queue */ @@ -622,6 +629,8 @@ int unique_len; /**< Length of unique field */ dev_t device; /**< Device number for mknod */ char *devname; /**< For /proc/interrupts */ + int minor; /**< Minor device number */ + int if_version; /**< Highest interface version set */ int blocked; /**< Blocked due to VC switch? */ struct proc_dir_entry *root; /**< Root for this device's entries */ @@ -679,6 +688,7 @@ /** \name Context support */ /*@{*/ int irq; /**< Interrupt used by board */ + int irq_enabled; /**< True if irq handler is enabled */ __volatile__ long context_flag; /**< Context swapping flag */ __volatile__ long interrupt_flag; /**< Interruption handler flag */ __volatile__ long dma_flag; /**< DMA dispatch flag */ @@ -714,7 +724,12 @@ #if __REALLY_HAVE_AGP drm_agp_head_t *agp; /**< AGP data */ #endif - struct pci_dev *pdev; /**< PCI device structure */ + + struct pci_dev *pdev; /**< PCI device structure */ + int pci_domain; /**< PCI bus domain number */ + int pci_bus; /**< PCI bus number */ + int pci_slot; /**< PCI slot number */ + int pci_func; /**< PCI function number */ #ifdef __alpha__ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) struct pci_controler *hose; @@ -804,8 +819,8 @@ #endif /* Misc. IOCTL support (drm_ioctl.h) */ -extern int DRM(irq_busid)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); +extern int DRM(irq_by_busid)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); extern int DRM(getunique)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int DRM(setunique)(struct inode *inode, struct file *filp, @@ -816,6 +831,8 @@ unsigned int cmd, unsigned long arg); extern int DRM(getstats)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int DRM(setversion)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); /* Context IOCTL support (drm_context.h) */ extern int DRM(resctx)( struct inode *inode, struct file *filp, @@ -900,12 +917,17 @@ extern void DRM(dma_takedown)(drm_device_t *dev); extern void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf); extern void DRM(reclaim_buffers)( struct file *filp ); -#if __HAVE_DMA_IRQ +#endif /* __HAVE_DMA */ + + /* IRQ support (drm_irq.h) */ +#if __HAVE_IRQ || __HAVE_DMA extern int DRM(control)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); -extern int DRM(irq_install)( drm_device_t *dev, int irq ); +#endif +#if __HAVE_IRQ +extern int DRM(irq_install)( drm_device_t *dev ); extern int DRM(irq_uninstall)( drm_device_t *dev ); -extern irqreturn_t DRM(dma_service)( DRM_IRQ_ARGS ); +extern irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS ); extern void DRM(driver_irq_preinstall)( drm_device_t *dev ); extern void DRM(driver_irq_postinstall)( drm_device_t *dev ); extern void DRM(driver_irq_uninstall)( drm_device_t *dev ); @@ -915,12 +937,11 @@ extern int DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq); extern void DRM(vbl_send_signals)( drm_device_t *dev ); #endif -#if __HAVE_DMA_IRQ_BH -extern void DRM(dma_immediate_bh)( void *dev ); +#if __HAVE_IRQ_BH +extern void DRM(irq_immediate_bh)( void *dev ); #endif #endif -#endif /* __HAVE_DMA */ #if __REALLY_HAVE_AGP /* AGP/GART support (drm_agpsupport.h) */ --- diff/drivers/char/drm/drm_bufs.h 2003-07-22 18:54:27.000000000 +0100 +++ source/drivers/char/drm/drm_bufs.h 2004-02-09 10:39:52.000000000 +0000 @@ -147,7 +147,9 @@ MTRR_TYPE_WRCOMB, 1 ); } #endif - map->handle = DRM(ioremap)( map->offset, map->size, dev ); + if (map->type == _DRM_REGISTERS) + map->handle = DRM(ioremap)( map->offset, map->size, + dev ); break; case _DRM_SHM: @@ -160,6 +162,12 @@ } map->offset = (unsigned long)map->handle; if ( map->flags & _DRM_CONTAINS_LOCK ) { + /* Prevent a 2nd X Server from creating a 2nd lock */ + if (dev->lock.hw_lock != NULL) { + vfree( map->handle ); + DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); + return -EBUSY; + } dev->sigdata.lock = dev->lock.hw_lock = map->handle; /* Pointer to lock */ } --- diff/drivers/char/drm/drm_dma.h 2003-07-22 18:54:27.000000000 +0100 +++ source/drivers/char/drm/drm_dma.h 2004-02-09 10:39:52.000000000 +0000 @@ -43,15 +43,6 @@ #ifndef __HAVE_DMA_RECLAIM #define __HAVE_DMA_RECLAIM 0 #endif -#ifndef __HAVE_SHARED_IRQ -#define __HAVE_SHARED_IRQ 0 -#endif - -#if __HAVE_SHARED_IRQ -#define DRM_IRQ_TYPE SA_SHIRQ -#else -#define DRM_IRQ_TYPE 0 -#endif #if __HAVE_DMA @@ -214,293 +205,11 @@ } #endif - - - -#if __HAVE_DMA_IRQ - -/** - * Install IRQ handler. - * - * \param dev DRM device. - * \param irq IRQ number. - * - * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver - * \c DRM(driver_irq_preinstall)() and \c DRM(driver_irq_postinstall)() functions - * before and after the installation. - */ -int DRM(irq_install)( drm_device_t *dev, int irq ) -{ - int ret; - - if ( !irq ) - return -EINVAL; - - down( &dev->struct_sem ); - - /* Driver must have been initialized */ - if ( !dev->dev_private ) { - up( &dev->struct_sem ); - return -EINVAL; - } - - if ( dev->irq ) { - up( &dev->struct_sem ); - return -EBUSY; - } - dev->irq = irq; - up( &dev->struct_sem ); - - DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq ); - - dev->context_flag = 0; - dev->interrupt_flag = 0; - dev->dma_flag = 0; - - dev->dma->next_buffer = NULL; - dev->dma->next_queue = NULL; - dev->dma->this_buffer = NULL; - -#if __HAVE_DMA_IRQ_BH - INIT_WORK(&dev->work, DRM(dma_immediate_bh), dev); -#endif - -#if __HAVE_VBL_IRQ - init_waitqueue_head(&dev->vbl_queue); - - spin_lock_init( &dev->vbl_lock ); - - INIT_LIST_HEAD( &dev->vbl_sigs.head ); - - dev->vbl_pending = 0; -#endif - - /* Before installing handler */ - DRM(driver_irq_preinstall)(dev); - - /* Install handler */ - ret = request_irq( dev->irq, DRM(dma_service), - DRM_IRQ_TYPE, dev->devname, dev ); - if ( ret < 0 ) { - down( &dev->struct_sem ); - dev->irq = 0; - up( &dev->struct_sem ); - return ret; - } - - /* After installing handler */ - DRM(driver_irq_postinstall)(dev); - - return 0; -} - -/** - * Uninstall the IRQ handler. - * - * \param dev DRM device. - * - * Calls the driver's \c DRM(driver_irq_uninstall)() function, and stops the irq. - */ -int DRM(irq_uninstall)( drm_device_t *dev ) -{ - int irq; - - down( &dev->struct_sem ); - irq = dev->irq; - dev->irq = 0; - up( &dev->struct_sem ); - - if ( !irq ) - return -EINVAL; - - DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq ); - - DRM(driver_irq_uninstall)( dev ); - - free_irq( irq, dev ); - - return 0; -} - -/** - * IRQ control ioctl. - * - * \param inode device inode. - * \param filp file pointer. - * \param cmd command. - * \param arg user argument, pointing to a drm_control structure. - * \return zero on success or a negative number on failure. - * - * Calls irq_install() or irq_uninstall() according to \p arg. - */ -int DRM(control)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_control_t ctl; - - if ( copy_from_user( &ctl, (drm_control_t *)arg, sizeof(ctl) ) ) - return -EFAULT; - - switch ( ctl.func ) { - case DRM_INST_HANDLER: - return DRM(irq_install)( dev, ctl.irq ); - case DRM_UNINST_HANDLER: - return DRM(irq_uninstall)( dev ); - default: - return -EINVAL; - } -} - -#if __HAVE_VBL_IRQ - -/** - * Wait for VBLANK. - * - * \param inode device inode. - * \param filp file pointer. - * \param cmd command. - * \param data user argument, pointing to a drm_wait_vblank structure. - * \return zero on success or a negative number on failure. - * - * Verifies the IRQ is installed. - * - * If a signal is requested checks if this task has already scheduled the same signal - * for the same vblank sequence number - nothing to be done in - * that case. If the number of tasks waiting for the interrupt exceeds 100 the - * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this - * task. - * - * If a signal is not requested, then calls vblank_wait(). - */ -int DRM(wait_vblank)( DRM_IOCTL_ARGS ) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_wait_vblank_t vblwait; - struct timeval now; - int ret = 0; - unsigned int flags; - - if (!dev->irq) - return -EINVAL; - - DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data, - sizeof(vblwait) ); - - switch ( vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK ) { - case _DRM_VBLANK_RELATIVE: - vblwait.request.sequence += atomic_read( &dev->vbl_received ); - vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; - case _DRM_VBLANK_ABSOLUTE: - break; - default: - return -EINVAL; - } - - flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; - - if ( flags & _DRM_VBLANK_SIGNAL ) { - unsigned long irqflags; - drm_vbl_sig_t *vbl_sig; - - vblwait.reply.sequence = atomic_read( &dev->vbl_received ); - - spin_lock_irqsave( &dev->vbl_lock, irqflags ); - - /* Check if this task has already scheduled the same signal - * for the same vblank sequence number; nothing to be done in - * that case - */ - list_for_each_entry( vbl_sig, &dev->vbl_sigs.head, head ) { - if (vbl_sig->sequence == vblwait.request.sequence - && vbl_sig->info.si_signo == vblwait.request.signal - && vbl_sig->task == current) - { - spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - goto done; - } - } - - if ( dev->vbl_pending >= 100 ) { - spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - return -EBUSY; - } - - dev->vbl_pending++; - - spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - - if ( !( vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) ) ) ) { - return -ENOMEM; - } - - memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) ); - - vbl_sig->sequence = vblwait.request.sequence; - vbl_sig->info.si_signo = vblwait.request.signal; - vbl_sig->task = current; - - spin_lock_irqsave( &dev->vbl_lock, irqflags ); - - list_add_tail( (struct list_head *) vbl_sig, &dev->vbl_sigs.head ); - - spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - } else { - ret = DRM(vblank_wait)( dev, &vblwait.request.sequence ); - - do_gettimeofday( &now ); - vblwait.reply.tval_sec = now.tv_sec; - vblwait.reply.tval_usec = now.tv_usec; - } - -done: - DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait, - sizeof(vblwait) ); - - return ret; -} - -/** - * Send the VBLANK signals. - * - * \param dev DRM device. - * - * Sends a signal for each task in drm_device::vbl_sigs and empties the list. - * - * If a signal is not requested, then calls vblank_wait(). +#if !__HAVE_IRQ +/* This stub DRM_IOCTL_CONTROL handler is for the drivers that used to require + * IRQs for DMA but no longer do. It maintains compatibility with the X Servers + * that try to use the control ioctl by simply returning success. */ -void DRM(vbl_send_signals)( drm_device_t *dev ) -{ - struct list_head *list, *tmp; - drm_vbl_sig_t *vbl_sig; - unsigned int vbl_seq = atomic_read( &dev->vbl_received ); - unsigned long flags; - - spin_lock_irqsave( &dev->vbl_lock, flags ); - - list_for_each_safe( list, tmp, &dev->vbl_sigs.head ) { - vbl_sig = list_entry( list, drm_vbl_sig_t, head ); - if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) { - vbl_sig->info.si_code = vbl_seq; - send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task ); - - list_del( list ); - - DRM_FREE( vbl_sig, sizeof(*vbl_sig) ); - - dev->vbl_pending--; - } - } - - spin_unlock_irqrestore( &dev->vbl_lock, flags ); -} - -#endif /* __HAVE_VBL_IRQ */ - -#else - int DRM(control)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -517,7 +226,6 @@ return -EINVAL; } } - -#endif /* __HAVE_DMA_IRQ */ +#endif #endif /* __HAVE_DMA */ --- diff/drivers/char/drm/drm_drv.h 2003-10-27 09:20:43.000000000 +0000 +++ source/drivers/char/drm/drm_drv.h 2004-02-09 10:39:52.000000000 +0000 @@ -58,8 +58,8 @@ #ifndef __HAVE_CTX_BITMAP #define __HAVE_CTX_BITMAP 0 #endif -#ifndef __HAVE_DMA_IRQ -#define __HAVE_DMA_IRQ 0 +#ifndef __HAVE_IRQ +#define __HAVE_IRQ 0 #endif #ifndef __HAVE_DMA_QUEUE #define __HAVE_DMA_QUEUE 0 @@ -126,6 +126,9 @@ #ifndef DRIVER_IOCTLS #define DRIVER_IOCTLS #endif +#ifndef DRIVER_OPEN_HELPER +#define DRIVER_OPEN_HELPER( priv, dev ) +#endif #ifndef DRIVER_FOPS #define DRIVER_FOPS \ static struct file_operations DRM(fops) = { \ @@ -159,15 +162,8 @@ #undef DRM_OPTIONS_FUNC #endif -/** - * The default number of instances (minor numbers) to initialize. - */ -#ifndef DRIVER_NUM_CARDS -#define DRIVER_NUM_CARDS 1 -#endif - -static drm_device_t *DRM(device); -static int *DRM(minor); +#define MAX_DEVICES 4 +static drm_device_t DRM(device)[MAX_DEVICES]; static int DRM(numdevs) = 0; DRIVER_FOPS; @@ -177,10 +173,13 @@ [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { DRM(version), 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { DRM(getunique), 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { DRM(getmagic), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_busid), 0, 1 }, +#if __HAVE_IRQ + [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_by_busid), 0, 1 }, +#endif [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = { DRM(getmap), 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = { DRM(getclient), 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { DRM(getstats), 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SET_VERSION)] = { DRM(setversion), 0, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { DRM(setunique), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { DRM(noop), 1, 1 }, @@ -222,9 +221,9 @@ [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { DRM(infobufs), 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { DRM(mapbufs), 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { DRM(freebufs), 1, 0 }, - - /* The DRM_IOCTL_DMA ioctl should be defined by the driver. - */ + /* The DRM_IOCTL_DMA ioctl should be defined by the driver. */ +#endif +#if __HAVE_IRQ || __HAVE_DMA [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control), 1, 1 }, #endif @@ -337,7 +336,7 @@ dev->queue_reserved = 0; dev->queue_slots = 0; dev->queuelist = NULL; - dev->irq = 0; + dev->irq_enabled = 0; dev->context_flag = 0; dev->interrupt_flag = 0; dev->dma_flag = 0; @@ -345,6 +344,7 @@ dev->last_switch = 0; dev->last_checked = 0; init_waitqueue_head( &dev->context_wait ); + dev->if_version = 0; dev->ctx_start = 0; dev->lck_start = 0; @@ -391,8 +391,8 @@ DRM_DEBUG( "\n" ); DRIVER_PRETAKEDOWN(); -#if __HAVE_DMA_IRQ - if ( dev->irq ) DRM(irq_uninstall)( dev ); +#if __HAVE_IRQ + if ( dev->irq_enabled ) DRM(irq_uninstall)( dev ); #endif down( &dev->struct_sem ); @@ -534,52 +534,111 @@ return 0; } -/** - * Figure out how many instances to initialize. - * - * \return number of cards found. - * - * Searches for every PCI card in \c DRIVER_CARD_LIST with matching vendor and device ids. - */ -static int drm_count_cards(void) +static drm_pci_id_list_t DRM(pciidlist)[] = { + DRIVER_PCI_IDS +}; + +static int DRM(probe)(struct pci_dev *pdev) { - int num = 0; -#if defined(DRIVER_CARD_LIST) - int i; - drm_pci_list_t *l; - u16 device, vendor; - struct pci_dev *pdev = NULL; + drm_device_t *dev; +#if __HAVE_CTX_BITMAP + int retcode; #endif + int i; + char *desc = NULL; DRM_DEBUG( "\n" ); -#if defined(DRIVER_COUNT_CARDS) - num = DRIVER_COUNT_CARDS(); -#elif defined(DRIVER_CARD_LIST) - for (i = 0, l = DRIVER_CARD_LIST; l[i].vendor != 0; i++) { - pdev = NULL; - vendor = l[i].vendor; - device = l[i].device; - if(device == 0xffff) device = PCI_ANY_ID; - if(vendor == 0xffff) vendor = PCI_ANY_ID; - while ((pdev = pci_find_device(vendor, device, pdev))) { - num++; + for (i = 0; DRM(pciidlist)[i].vendor != 0; i++) { + if ((DRM(pciidlist)[i].vendor == pdev->vendor) && + (DRM(pciidlist)[i].device == pdev->device)) { + desc = DRM(pciidlist)[i].name; } } + if (desc == NULL) + return -ENODEV; + + if (DRM(numdevs) >= MAX_DEVICES) + return -ENODEV; + + dev = &(DRM(device)[DRM(numdevs)]); + + memset( (void *)dev, 0, sizeof(*dev) ); + dev->count_lock = SPIN_LOCK_UNLOCKED; + init_timer( &dev->timer ); + sema_init( &dev->struct_sem, 1 ); + + if ((dev->minor = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0) + return -EPERM; + dev->device = MKDEV(DRM_MAJOR, dev->minor ); + dev->name = DRIVER_NAME; + + dev->pdev = pdev; +#ifdef __alpha__ + dev->hose = pdev->sysdata; + dev->pci_domain = dev->hose->bus->number; #else - num = DRIVER_NUM_CARDS; + dev->pci_domain = 0; +#endif + dev->pci_bus = pdev->bus->number; + dev->pci_slot = PCI_SLOT(pdev->devfn); + dev->pci_func = PCI_FUNC(pdev->devfn); + dev->irq = pdev->irq; + + DRIVER_PREINIT(); + +#if __REALLY_HAVE_AGP + dev->agp = DRM(agp_init)(); +#if __MUST_HAVE_AGP + if ( dev->agp == NULL ) { + DRM_ERROR( "Cannot initialize the agpgart module.\n" ); + DRM(stub_unregister)(dev->minor); + DRM(takedown)( dev ); + return -ENOMEM; + } +#endif +#if __REALLY_HAVE_MTRR + if (dev->agp) + dev->agp->agp_mtrr = mtrr_add( dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size*1024*1024, + MTRR_TYPE_WRCOMB, + 1 ); +#endif +#endif + +#if __HAVE_CTX_BITMAP + retcode = DRM(ctxbitmap_init)( dev ); + if( retcode ) { + DRM_ERROR( "Cannot allocate memory for context bitmap.\n" ); + DRM(stub_unregister)(dev->minor); + DRM(takedown)( dev ); + return retcode; + } #endif - DRM_DEBUG("numdevs = %d\n", num); - return num; + DRM(numdevs)++; /* no errors, mark it reserved */ + + DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d: %s\n", + DRIVER_NAME, + DRIVER_MAJOR, + DRIVER_MINOR, + DRIVER_PATCHLEVEL, + DRIVER_DATE, + dev->minor, + desc ); + + DRIVER_POSTINIT(); + + return 0; } + /** * Module initialization. Called via init_module at module load time, or via * linux/init/main.c (this is not currently supported). * * \return zero on success or a negative number on failure. * - * Allocates and initialize an array of drm_device structures, and attempts to + * Initializes an array of drm_device structures, and attempts to * initialize all available devices, using consecutive minors, registering the * stubs and initializing the AGP device. * @@ -588,88 +647,19 @@ */ static int __init drm_init( void ) { + struct pci_dev *pdev = NULL; - drm_device_t *dev; - int i; -#if __HAVE_CTX_BITMAP - int retcode; -#endif DRM_DEBUG( "\n" ); #ifdef MODULE DRM(parse_options)( drm_opts ); #endif - DRM(numdevs) = drm_count_cards(); - /* Force at least one instance. */ - if (DRM(numdevs) <= 0) - DRM(numdevs) = 1; - - DRM(device) = kmalloc(sizeof(*DRM(device)) * DRM(numdevs), GFP_KERNEL); - if (!DRM(device)) { - return -ENOMEM; - } - DRM(minor) = kmalloc(sizeof(*DRM(minor)) * DRM(numdevs), GFP_KERNEL); - if (!DRM(minor)) { - kfree(DRM(device)); - return -ENOMEM; - } - - DRIVER_PREINIT(); - DRM(mem_init)(); - for (i = 0; i < DRM(numdevs); i++) { - dev = &(DRM(device)[i]); - memset( (void *)dev, 0, sizeof(*dev) ); - dev->count_lock = SPIN_LOCK_UNLOCKED; - init_timer( &dev->timer ); - sema_init( &dev->struct_sem, 1 ); - - if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0) - return -EPERM; - dev->device = MKDEV(DRM_MAJOR, DRM(minor)[i] ); - dev->name = DRIVER_NAME; - -#if __REALLY_HAVE_AGP - dev->agp = DRM(agp_init)(); -#if __MUST_HAVE_AGP - if ( dev->agp == NULL ) { - DRM_ERROR( "Cannot initialize the agpgart module.\n" ); - DRM(stub_unregister)(DRM(minor)[i]); - DRM(takedown)( dev ); - return -EINVAL; - } -#endif -#if __REALLY_HAVE_MTRR - if (dev->agp) - dev->agp->agp_mtrr = mtrr_add( dev->agp->agp_info.aper_base, - dev->agp->agp_info.aper_size*1024*1024, - MTRR_TYPE_WRCOMB, - 1 ); -#endif -#endif - -#if __HAVE_CTX_BITMAP - retcode = DRM(ctxbitmap_init)( dev ); - if( retcode ) { - DRM_ERROR( "Cannot allocate memory for context bitmap.\n" ); - DRM(stub_unregister)(DRM(minor)[i]); - DRM(takedown)( dev ); - return retcode; - } -#endif - DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d\n", - DRIVER_NAME, - DRIVER_MAJOR, - DRIVER_MINOR, - DRIVER_PATCHLEVEL, - DRIVER_DATE, - DRM(minor)[i] ); + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { + DRM(probe)(pdev); } - - DRIVER_POSTINIT(); - return 0; } @@ -689,10 +679,10 @@ for (i = DRM(numdevs) - 1; i >= 0; i--) { dev = &(DRM(device)[i]); - if ( DRM(stub_unregister)(DRM(minor)[i]) ) { + if ( DRM(stub_unregister)(dev->minor) ) { DRM_ERROR( "Cannot unload module\n" ); } else { - DRM_DEBUG("minor %d unregistered\n", DRM(minor)[i]); + DRM_DEBUG("minor %d unregistered\n", dev->minor); if (i == 0) { DRM_INFO( "Module unloaded\n" ); } @@ -722,8 +712,6 @@ #endif } DRIVER_POSTCLEANUP(); - kfree(DRM(minor)); - kfree(DRM(device)); DRM(numdevs) = 0; } @@ -795,7 +783,7 @@ int i; for (i = 0; i < DRM(numdevs); i++) { - if (iminor(inode) == DRM(minor)[i]) { + if (iminor(inode) == DRM(device)[i].minor) { dev = &(DRM(device)[i]); break; } --- diff/drivers/char/drm/drm_fops.h 2003-10-09 09:47:16.000000000 +0100 +++ source/drivers/char/drm/drm_fops.h 2004-02-09 10:39:52.000000000 +0000 @@ -72,6 +72,8 @@ priv->authenticated = capable(CAP_SYS_ADMIN); priv->lock_count = 0; + DRIVER_OPEN_HELPER( priv, dev ); + down(&dev->struct_sem); if (!dev->file_last) { priv->next = NULL; --- diff/drivers/char/drm/drm_ioctl.h 2003-07-22 18:54:27.000000000 +0100 +++ source/drivers/char/drm/drm_ioctl.h 2004-02-09 10:39:52.000000000 +0000 @@ -35,69 +35,7 @@ #include "drmP.h" - -/** - * Get interrupt from bus id. - * - * \param inode device inode. - * \param filp file pointer. - * \param cmd command. - * \param arg user argument, pointing to a drm_irq_busid structure. - * \return zero on success or a negative number on failure. - * - * Finds the PCI device with the specified bus id and gets its IRQ number. - */ -int DRM(irq_busid)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_irq_busid_t p; - struct pci_dev *dev; - - if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p))) - return -EFAULT; -#ifdef __alpha__ - { - int domain = p.busnum >> 8; - p.busnum &= 0xff; - - /* - * Find the hose the device is on (the domain number is the - * hose index) and offset the bus by the root bus of that - * hose. - */ - for(dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL); - dev; - dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,dev)) { - struct pci_controller *hose = dev->sysdata; - - if (hose->index == domain) { - p.busnum += hose->bus->number; - break; - } - } - } -#endif - dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum)); - if (!dev) { - DRM_ERROR("pci_find_slot failed for %d:%d:%d\n", - p.busnum, p.devnum, p.funcnum); - p.irq = 0; - goto out; - } - if (pci_enable_device(dev) != 0) { - DRM_ERROR("pci_enable_device failed for %d:%d:%d\n", - p.busnum, p.devnum, p.funcnum); - p.irq = 0; - goto out; - } - p.irq = dev->irq; - out: - DRM_DEBUG("%d:%d:%d => IRQ %d\n", - p.busnum, p.devnum, p.funcnum, p.irq); - if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p))) - return -EFAULT; - return 0; -} +#include /** * Get the bus id. @@ -138,8 +76,10 @@ * \param arg user argument, pointing to a drm_unique structure. * \return zero on success or a negative number on failure. * - * Copies the bus id from userspace into drm_device::unique, and searches for - * the respective PCI device, updating drm_device::pdev. + * Copies the bus id from userspace into drm_device::unique, and verifies that + * it matches the device this DRM is attached to (EINVAL otherwise). Deprecated + * in interface version 1.1 and will return EBUSY when setversion has requested + * version 1.1 or greater. */ int DRM(setunique)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) @@ -147,6 +87,7 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_unique_t u; + int domain, bus, slot, func, ret; if (dev->unique_len || dev->unique) return -EBUSY; @@ -164,55 +105,42 @@ dev->devname = DRM(alloc)(strlen(dev->name) + strlen(dev->unique) + 2, DRM_MEM_DRIVER); - if(!dev->devname) { - DRM(free)(dev->devname, sizeof(*dev->devname), DRM_MEM_DRIVER); + if (!dev->devname) return -ENOMEM; - } + sprintf(dev->devname, "%s@%s", dev->name, dev->unique); - do { - struct pci_dev *pci_dev; - int domain, b, d, f; - char *p; - - for(p = dev->unique; p && *p && *p != ':'; p++); - if (!p || !*p) break; - b = (int)simple_strtoul(p+1, &p, 10); - if (*p != ':') break; - d = (int)simple_strtoul(p+1, &p, 10); - if (*p != ':') break; - f = (int)simple_strtoul(p+1, &p, 10); - if (*p) break; - - domain = b >> 8; - b &= 0xff; - -#ifdef __alpha__ - /* - * Find the hose the device is on (the domain number is the - * hose index) and offset the bus by the root bus of that - * hose. - */ - for(pci_dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL); - pci_dev; - pci_dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,pci_dev)) { - struct pci_controller *hose = pci_dev->sysdata; - - if (hose->index == domain) { - b += hose->bus->number; - break; - } - } -#endif + /* Return error if the busid submitted doesn't match the device's actual + * busid. + */ + ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func); + if (ret != 3) + return DRM_ERR(EINVAL); + domain = bus >> 8; + bus &= 0xff; + + if ((domain != dev->pci_domain) || + (bus != dev->pci_bus) || + (slot != dev->pci_slot) || + (func != dev->pci_func)) + return -EINVAL; - pci_dev = pci_find_slot(b, PCI_DEVFN(d,f)); - if (pci_dev) { - dev->pdev = pci_dev; -#ifdef __alpha__ - dev->hose = pci_dev->sysdata; -#endif - } - } while(0); + return 0; +} + +static int +DRM(set_busid)(drm_device_t *dev) +{ + if (dev->unique != NULL) + return EBUSY; + + dev->unique_len = 20; + dev->unique = DRM(alloc)(dev->unique_len + 1, DRM_MEM_DRIVER); + if (dev->unique == NULL) + return ENOMEM; + + snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", + dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func); return 0; } @@ -363,3 +291,48 @@ return -EFAULT; return 0; } + +#define DRM_IF_MAJOR 1 +#define DRM_IF_MINOR 2 + +int DRM(setversion)(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_set_version_t sv; + drm_set_version_t retv; + int if_version; + + DRM_COPY_FROM_USER_IOCTL(sv, (drm_set_version_t *)data, sizeof(sv)); + + retv.drm_di_major = DRM_IF_MAJOR; + retv.drm_di_minor = DRM_IF_MINOR; + retv.drm_dd_major = DRIVER_MAJOR; + retv.drm_dd_minor = DRIVER_MINOR; + + DRM_COPY_TO_USER_IOCTL((drm_set_version_t *)data, retv, sizeof(sv)); + + if (sv.drm_di_major != -1) { + if (sv.drm_di_major != DRM_IF_MAJOR || + sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR) + return EINVAL; + if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_dd_minor); + dev->if_version = DRM_MAX(if_version, dev->if_version); + if (sv.drm_di_minor >= 1) { + /* + * Version 1.1 includes tying of DRM to specific device + */ + DRM(set_busid)(dev); + } + } + + if (sv.drm_dd_major != -1) { + if (sv.drm_dd_major != DRIVER_MAJOR || + sv.drm_dd_minor < 0 || sv.drm_dd_minor > DRIVER_MINOR) + return EINVAL; +#ifdef DRIVER_SETVERSION + DRIVER_SETVERSION(dev, &sv); +#endif + } + return 0; +} + --- diff/drivers/char/drm/drm_os_linux.h 2003-09-30 15:46:12.000000000 +0100 +++ source/drivers/char/drm/drm_os_linux.h 2004-02-09 10:39:52.000000000 +0000 @@ -62,8 +62,12 @@ verify_area( VERIFY_READ, uaddr, size ) #define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3) \ __copy_from_user(arg1, arg2, arg3) +#define DRM_COPY_TO_USER_UNCHECKED(arg1, arg2, arg3) \ + __copy_to_user(arg1, arg2, arg3) #define DRM_GET_USER_UNCHECKED(val, uaddr) \ __get_user(val, uaddr) +#define DRM_PUT_USER_UNCHECKED(uaddr, val) \ + __put_user(val, uaddr) /** 'malloc' without the overhead of DRM(alloc)() */ @@ -71,6 +75,8 @@ /** 'free' without the overhead of DRM(free)() */ #define DRM_FREE(x,size) kfree(x) +#define DRM_GET_PRIV_WITH_RETURN(_priv, _filp) _priv = _filp->private_data + /** * Get the pointer to the SAREA. * --- diff/drivers/char/drm/gamma.h 2003-05-21 11:50:14.000000000 +0100 +++ source/drivers/char/drm/gamma.h 2004-02-09 10:39:52.000000000 +0000 @@ -53,6 +53,10 @@ [DRM_IOCTL_NR(DRM_IOCTL_GAMMA_INIT)] = { gamma_dma_init, 1, 1 }, \ [DRM_IOCTL_NR(DRM_IOCTL_GAMMA_COPY)] = { gamma_dma_copy, 1, 1 } +#define DRIVER_PCI_IDS \ + {0x3d3d, 0x0008, 0, "3DLabs GLINT Gamma G1"}, \ + {0, 0, 0, NULL} + #define IOCTL_TABLE_NAME DRM(ioctls) #define IOCTL_FUNC_NAME DRM(ioctl) @@ -104,8 +108,8 @@ return 0; \ } while (0) -#define __HAVE_DMA_IRQ 1 -#define __HAVE_DMA_IRQ_BH 1 +#define __HAVE_IRQ 1 +#define __HAVE_IRQ_BH 1 #define DRIVER_AGP_BUFFERS_MAP( dev ) \ ((drm_gamma_private_t *)((dev)->dev_private))->buffers --- diff/drivers/char/drm/gamma_dma.c 2003-09-30 15:46:12.000000000 +0100 +++ source/drivers/char/drm/gamma_dma.c 2004-02-09 10:39:52.000000000 +0000 @@ -116,7 +116,7 @@ return (!GAMMA_READ(GAMMA_DMACOUNT)); } -irqreturn_t gamma_dma_service( DRM_IRQ_ARGS ) +irqreturn_t gamma_irq_handler( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *)arg; drm_device_dma_t *dma = dev->dma; @@ -262,7 +262,7 @@ gamma_dma_schedule((drm_device_t *)dev, 0); } -void gamma_dma_immediate_bh(void *dev) +void gamma_irq_immediate_bh(void *dev) { gamma_dma_schedule(dev, 0); } @@ -656,12 +656,12 @@ { DRM_DEBUG( "%s\n", __FUNCTION__ ); -#if _HAVE_DMA_IRQ +#if __HAVE_IRQ /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. */ - if ( dev->irq ) DRM(irq_uninstall)(dev); + if ( dev->irq_enabled ) DRM(irq_uninstall)(dev); #endif if ( dev->dev_private ) { --- diff/drivers/char/drm/gamma_drv.c 2003-05-21 11:50:14.000000000 +0100 +++ source/drivers/char/drm/gamma_drv.c 2004-02-09 10:39:52.000000000 +0000 @@ -48,6 +48,7 @@ #include "drm_fops.h" #include "drm_init.h" #include "drm_ioctl.h" +#include "drm_irq.h" #include "gamma_lists.h" /* NOTE */ #include "drm_lock.h" #include "gamma_lock.h" /* NOTE */ --- diff/drivers/char/drm/i810.h 2003-08-26 10:00:52.000000000 +0100 +++ source/drivers/char/drm/i810.h 2004-02-09 10:39:52.000000000 +0000 @@ -77,7 +77,14 @@ [DRM_IOCTL_NR(DRM_IOCTL_I810_MC)] = { i810_dma_mc, 1, 1 }, \ [DRM_IOCTL_NR(DRM_IOCTL_I810_RSTATUS)] = { i810_rstatus, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_I810_FLIP)] = { i810_flip_bufs, 1, 0 } - + +#define DRIVER_PCI_IDS \ + {0x8086, 0x7121, 0, "Intel i810 GMCH"}, \ + {0x8086, 0x7123, 0, "Intel i810-DC100 GMCH"}, \ + {0x8086, 0x7125, 0, "Intel i810E GMCH"}, \ + {0x8086, 0x1132, 0, "Intel i815 GMCH"}, \ + {0, 0, 0, NULL} + #define __HAVE_COUNTERS 4 #define __HAVE_COUNTER6 _DRM_STAT_IRQ @@ -112,7 +119,7 @@ * a noop stub is generated for compatibility. */ /* XXX: Add vblank support? */ -#define __HAVE_DMA_IRQ 0 +#define __HAVE_IRQ 0 /* Buffer customization: */ --- diff/drivers/char/drm/i810_dma.c 2003-09-30 15:46:12.000000000 +0100 +++ source/drivers/char/drm/i810_dma.c 2004-02-09 10:39:52.000000000 +0000 @@ -53,41 +53,41 @@ static inline void i810_print_status_page(drm_device_t *dev) { - drm_device_dma_t *dma = dev->dma; - drm_i810_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_i810_private_t *dev_priv = dev->dev_private; u32 *temp = dev_priv->hw_status_page; - int i; + int i; - DRM_DEBUG( "hw_status: Interrupt Status : %x\n", temp[0]); - DRM_DEBUG( "hw_status: LpRing Head ptr : %x\n", temp[1]); - DRM_DEBUG( "hw_status: IRing Head ptr : %x\n", temp[2]); - DRM_DEBUG( "hw_status: Reserved : %x\n", temp[3]); + DRM_DEBUG( "hw_status: Interrupt Status : %x\n", temp[0]); + DRM_DEBUG( "hw_status: LpRing Head ptr : %x\n", temp[1]); + DRM_DEBUG( "hw_status: IRing Head ptr : %x\n", temp[2]); + DRM_DEBUG( "hw_status: Reserved : %x\n", temp[3]); DRM_DEBUG( "hw_status: Last Render: %x\n", temp[4]); - DRM_DEBUG( "hw_status: Driver Counter : %d\n", temp[5]); - for(i = 6; i < dma->buf_count + 6; i++) { - DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]); + DRM_DEBUG( "hw_status: Driver Counter : %d\n", temp[5]); + for(i = 6; i < dma->buf_count + 6; i++) { + DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]); } } static drm_buf_t *i810_freelist_get(drm_device_t *dev) { - drm_device_dma_t *dma = dev->dma; + drm_device_dma_t *dma = dev->dma; int i; - int used; + int used; /* Linear search might not be the best solution */ - for (i = 0; i < dma->buf_count; i++) { - drm_buf_t *buf = dma->buflist[ i ]; - drm_i810_buf_priv_t *buf_priv = buf->dev_private; + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; /* In use is already a pointer */ - used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, + used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, I810_BUF_CLIENT); if (used == I810_BUF_FREE) { return buf; } } - return NULL; + return NULL; } /* This should only be called if the buffer is not sent to the hardware @@ -96,17 +96,17 @@ static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf) { - drm_i810_buf_priv_t *buf_priv = buf->dev_private; - int used; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + int used; - /* In use is already a pointer */ - used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE); + /* In use is already a pointer */ + used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE); if (used != I810_BUF_CLIENT) { - DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx); - return -EINVAL; + DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx); + return -EINVAL; } - return 0; + return 0; } static struct file_operations i810_buffer_fops = { @@ -135,7 +135,7 @@ vma->vm_flags |= (VM_IO | VM_DONTCOPY); vma->vm_file = filp; - buf_priv->currently_mapped = I810_BUF_MAPPED; + buf_priv->currently_mapped = I810_BUF_MAPPED; unlock_kernel(); if (remap_page_range(DRM_RPR_ARG(vma) vma->vm_start, @@ -150,8 +150,8 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_i810_buf_priv_t *buf_priv = buf->dev_private; - drm_i810_private_t *dev_priv = dev->dev_private; - struct file_operations *old_fops; + drm_i810_private_t *dev_priv = dev->dev_private; + struct file_operations *old_fops; int retcode = 0; if (buf_priv->currently_mapped == I810_BUF_MAPPED) @@ -192,8 +192,8 @@ (size_t) buf->total); up_write(¤t->mm->mmap_sem); - buf_priv->currently_mapped = I810_BUF_UNMAPPED; - buf_priv->virtual = 0; + buf_priv->currently_mapped = I810_BUF_UNMAPPED; + buf_priv->virtual = 0; return retcode; } @@ -208,22 +208,22 @@ buf = i810_freelist_get(dev); if (!buf) { retcode = -ENOMEM; - DRM_DEBUG("retcode=%d\n", retcode); + DRM_DEBUG("retcode=%d\n", retcode); return retcode; } retcode = i810_map_buffer(buf, filp); if (retcode) { i810_freelist_put(dev, buf); - DRM_ERROR("mapbuf failed, retcode %d\n", retcode); + DRM_ERROR("mapbuf failed, retcode %d\n", retcode); return retcode; } buf->filp = filp; buf_priv = buf->dev_private; d->granted = 1; - d->request_idx = buf->idx; - d->request_size = buf->total; - d->virtual = buf_priv->virtual; + d->request_idx = buf->idx; + d->request_size = buf->total; + d->virtual = buf_priv->virtual; return retcode; } @@ -232,33 +232,33 @@ { drm_device_dma_t *dma = dev->dma; -#if _HAVE_DMA_IRQ +#if __HAVE_IRQ /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. */ - if (dev->irq) DRM(irq_uninstall)(dev); + if (dev->irq_enabled) DRM(irq_uninstall)(dev); #endif if (dev->dev_private) { int i; - drm_i810_private_t *dev_priv = - (drm_i810_private_t *) dev->dev_private; + drm_i810_private_t *dev_priv = + (drm_i810_private_t *) dev->dev_private; if (dev_priv->ring.virtual_start) { - DRM(ioremapfree)((void *) dev_priv->ring.virtual_start, + DRM(ioremapfree)((void *) dev_priv->ring.virtual_start, dev_priv->ring.Size, dev); } - if (dev_priv->hw_status_page) { - pci_free_consistent(dev->pdev, PAGE_SIZE, + if (dev_priv->hw_status_page) { + pci_free_consistent(dev->pdev, PAGE_SIZE, dev_priv->hw_status_page, dev_priv->dma_status_page); - /* Need to rewrite hardware status page */ - I810_WRITE(0x02080, 0x1ffff000); + /* Need to rewrite hardware status page */ + I810_WRITE(0x02080, 0x1ffff000); } - DRM(free)(dev->dev_private, sizeof(drm_i810_private_t), + DRM(free)(dev->dev_private, sizeof(drm_i810_private_t), DRM_MEM_DRIVER); - dev->dev_private = NULL; + dev->dev_private = NULL; for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; @@ -267,73 +267,73 @@ DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total, dev); } } - return 0; + return 0; } static int i810_wait_ring(drm_device_t *dev, int n) { - drm_i810_private_t *dev_priv = dev->dev_private; - drm_i810_ring_buffer_t *ring = &(dev_priv->ring); - int iters = 0; - unsigned long end; + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_ring_buffer_t *ring = &(dev_priv->ring); + int iters = 0; + unsigned long end; unsigned int last_head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; end = jiffies + (HZ*3); - while (ring->space < n) { - ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; - ring->space = ring->head - (ring->tail+8); + while (ring->space < n) { + ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->space = ring->head - (ring->tail+8); if (ring->space < 0) ring->space += ring->Size; - + if (ring->head != last_head) { end = jiffies + (HZ*3); last_head = ring->head; } - iters++; + iters++; if (time_before(end, jiffies)) { - DRM_ERROR("space: %d wanted %d\n", ring->space, n); - DRM_ERROR("lockup\n"); - goto out_wait_ring; + DRM_ERROR("space: %d wanted %d\n", ring->space, n); + DRM_ERROR("lockup\n"); + goto out_wait_ring; } udelay(1); } out_wait_ring: - return iters; + return iters; } static void i810_kernel_lost_context(drm_device_t *dev) { - drm_i810_private_t *dev_priv = dev->dev_private; - drm_i810_ring_buffer_t *ring = &(dev_priv->ring); + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_ring_buffer_t *ring = &(dev_priv->ring); - ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; - ring->tail = I810_READ(LP_RING + RING_TAIL); - ring->space = ring->head - (ring->tail+8); - if (ring->space < 0) ring->space += ring->Size; + ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->tail = I810_READ(LP_RING + RING_TAIL); + ring->space = ring->head - (ring->tail+8); + if (ring->space < 0) ring->space += ring->Size; } static int i810_freelist_init(drm_device_t *dev, drm_i810_private_t *dev_priv) { - drm_device_dma_t *dma = dev->dma; - int my_idx = 24; - u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx); - int i; + drm_device_dma_t *dma = dev->dma; + int my_idx = 24; + u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx); + int i; if (dma->buf_count > 1019) { - /* Not enough space in the status page for the freelist */ - return -EINVAL; + /* Not enough space in the status page for the freelist */ + return -EINVAL; } - for (i = 0; i < dma->buf_count; i++) { - drm_buf_t *buf = dma->buflist[ i ]; - drm_i810_buf_priv_t *buf_priv = buf->dev_private; + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; - buf_priv->in_use = hw_status++; - buf_priv->my_use_idx = my_idx; - my_idx += 4; + buf_priv->in_use = hw_status++; + buf_priv->my_use_idx = my_idx; + my_idx += 4; - *buf_priv->in_use = I810_BUF_FREE; + *buf_priv->in_use = I810_BUF_FREE; buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address, buf->total, dev); @@ -347,7 +347,7 @@ { struct list_head *list; - memset(dev_priv, 0, sizeof(drm_i810_private_t)); + memset(dev_priv, 0, sizeof(drm_i810_private_t)); list_for_each(list, &dev->maplist->head) { drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head); @@ -355,51 +355,51 @@ r_list->map->type == _DRM_SHM && r_list->map->flags & _DRM_CONTAINS_LOCK ) { dev_priv->sarea_map = r_list->map; - break; - } - } + break; + } + } if (!dev_priv->sarea_map) { dev->dev_private = (void *)dev_priv; - i810_dma_cleanup(dev); - DRM_ERROR("can not find sarea!\n"); - return -EINVAL; + i810_dma_cleanup(dev); + DRM_ERROR("can not find sarea!\n"); + return -EINVAL; } DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset ); if (!dev_priv->mmio_map) { dev->dev_private = (void *)dev_priv; - i810_dma_cleanup(dev); - DRM_ERROR("can not find mmio map!\n"); - return -EINVAL; + i810_dma_cleanup(dev); + DRM_ERROR("can not find mmio map!\n"); + return -EINVAL; } DRM_FIND_MAP( dev_priv->buffer_map, init->buffers_offset ); if (!dev_priv->buffer_map) { dev->dev_private = (void *)dev_priv; - i810_dma_cleanup(dev); - DRM_ERROR("can not find dma buffer map!\n"); - return -EINVAL; + i810_dma_cleanup(dev); + DRM_ERROR("can not find dma buffer map!\n"); + return -EINVAL; } dev_priv->sarea_priv = (drm_i810_sarea_t *) ((u8 *)dev_priv->sarea_map->handle + init->sarea_priv_offset); - dev_priv->ring.Start = init->ring_start; - dev_priv->ring.End = init->ring_end; - dev_priv->ring.Size = init->ring_size; + dev_priv->ring.Start = init->ring_start; + dev_priv->ring.End = init->ring_end; + dev_priv->ring.Size = init->ring_size; - dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base + + dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base + init->ring_start, init->ring_size, dev); - if (dev_priv->ring.virtual_start == NULL) { + if (dev_priv->ring.virtual_start == NULL) { dev->dev_private = (void *) dev_priv; - i810_dma_cleanup(dev); - DRM_ERROR("can not ioremap virtual address for" + i810_dma_cleanup(dev); + DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); - return -ENOMEM; + return -ENOMEM; } - dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; dev_priv->w = init->w; dev_priv->h = init->h; @@ -415,33 +415,33 @@ dev_priv->back_di1 = init->back_offset | init->pitch_bits; dev_priv->zi1 = init->depth_offset | init->pitch_bits; - /* Program Hardware Status Page */ - dev_priv->hw_status_page = + /* Program Hardware Status Page */ + dev_priv->hw_status_page = pci_alloc_consistent(dev->pdev, PAGE_SIZE, &dev_priv->dma_status_page); - if (!dev_priv->hw_status_page) { + if (!dev_priv->hw_status_page) { dev->dev_private = (void *)dev_priv; i810_dma_cleanup(dev); DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; } - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); I810_WRITE(0x02080, dev_priv->dma_status_page); - DRM_DEBUG("Enabled hardware status page\n"); + DRM_DEBUG("Enabled hardware status page\n"); - /* Now we need to init our freelist */ + /* Now we need to init our freelist */ if (i810_freelist_init(dev, dev_priv) != 0) { dev->dev_private = (void *)dev_priv; - i810_dma_cleanup(dev); - DRM_ERROR("Not enough space in the status page for" + i810_dma_cleanup(dev); + DRM_ERROR("Not enough space in the status page for" " the freelist\n"); - return -ENOMEM; + return -ENOMEM; } dev->dev_private = (void *)dev_priv; - return 0; + return 0; } /* i810 DRM version 1.1 used a smaller init structure with different @@ -476,12 +476,12 @@ /* This is a v1.1 client, fix the params */ DRM_INFO("Using PRE v1.2 init.\n"); - init->pitch_bits = init->h; - init->pitch = init->w; - init->h = init->overlay_physical; - init->w = init->overlay_offset; - init->overlay_physical = 0; - init->overlay_offset = 0; + init->pitch_bits = init->h; + init->pitch = init->w; + init->h = init->overlay_physical; + init->w = init->overlay_offset; + init->overlay_physical = 0; + init->overlay_offset = 0; } return 0; @@ -490,55 +490,55 @@ int i810_dma_init(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_i810_private_t *dev_priv; - drm_i810_init_t init; - int retcode = 0; + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i810_private_t *dev_priv; + drm_i810_init_t init; + int retcode = 0; /* Get only the init func */ if (copy_from_user(&init, (void *)arg, sizeof(drm_i810_init_func_t))) return -EFAULT; - switch(init.func) { - case I810_INIT_DMA: - /* This case is for backward compatibility. It + switch(init.func) { + case I810_INIT_DMA: + /* This case is for backward compatibility. It * handles XFree 4.1.0 and 4.2.0, and has to * do some parameter checking as described below. * It will someday go away. */ retcode = i810_dma_init_compat(&init, arg); - if (retcode) + if (retcode) return retcode; - dev_priv = DRM(alloc)(sizeof(drm_i810_private_t), + dev_priv = DRM(alloc)(sizeof(drm_i810_private_t), DRM_MEM_DRIVER); - if (dev_priv == NULL) - return -ENOMEM; - retcode = i810_dma_initialize(dev, dev_priv, &init); + if (dev_priv == NULL) + return -ENOMEM; + retcode = i810_dma_initialize(dev, dev_priv, &init); break; default: - case I810_INIT_DMA_1_4: + case I810_INIT_DMA_1_4: DRM_INFO("Using v1.4 init.\n"); - if (copy_from_user(&init, (drm_i810_init_t *)arg, + if (copy_from_user(&init, (drm_i810_init_t *)arg, sizeof(drm_i810_init_t))) { return -EFAULT; } - dev_priv = DRM(alloc)(sizeof(drm_i810_private_t), + dev_priv = DRM(alloc)(sizeof(drm_i810_private_t), DRM_MEM_DRIVER); if (dev_priv == NULL) return -ENOMEM; - retcode = i810_dma_initialize(dev, dev_priv, &init); + retcode = i810_dma_initialize(dev, dev_priv, &init); break; - case I810_CLEANUP_DMA: - DRM_INFO("DMA Cleanup\n"); - retcode = i810_dma_cleanup(dev); - break; + case I810_CLEANUP_DMA: + DRM_INFO("DMA Cleanup\n"); + retcode = i810_dma_cleanup(dev); + break; } - return retcode; + return retcode; } @@ -552,7 +552,7 @@ static void i810EmitContextVerified( drm_device_t *dev, volatile unsigned int *code ) { - drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_private_t *dev_priv = dev->dev_private; int i, j = 0; unsigned int tmp; RING_LOCALS; @@ -586,7 +586,7 @@ static void i810EmitTexVerified( drm_device_t *dev, volatile unsigned int *code ) { - drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_private_t *dev_priv = dev->dev_private; int i, j = 0; unsigned int tmp; RING_LOCALS; @@ -622,7 +622,7 @@ static void i810EmitDestVerified( drm_device_t *dev, volatile unsigned int *code ) { - drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_private_t *dev_priv = dev->dev_private; unsigned int tmp; RING_LOCALS; @@ -658,8 +658,8 @@ static void i810EmitState( drm_device_t *dev ) { - drm_i810_private_t *dev_priv = dev->dev_private; - drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int dirty = sarea_priv->dirty; DRM_DEBUG("%s %x\n", __FUNCTION__, dirty); @@ -693,8 +693,8 @@ unsigned int clear_color, unsigned int clear_zval ) { - drm_i810_private_t *dev_priv = dev->dev_private; - drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; int nbox = sarea_priv->nbox; drm_clip_rect_t *pbox = sarea_priv->boxes; int pitch = dev_priv->pitch; @@ -703,17 +703,17 @@ RING_LOCALS; if ( dev_priv->current_page == 1 ) { - unsigned int tmp = flags; - + unsigned int tmp = flags; + flags &= ~(I810_FRONT | I810_BACK); if (tmp & I810_FRONT) flags |= I810_BACK; if (tmp & I810_BACK) flags |= I810_FRONT; } - i810_kernel_lost_context(dev); + i810_kernel_lost_context(dev); - if (nbox > I810_NR_SAREA_CLIPRECTS) - nbox = I810_NR_SAREA_CLIPRECTS; + if (nbox > I810_NR_SAREA_CLIPRECTS) + nbox = I810_NR_SAREA_CLIPRECTS; for (i = 0 ; i < nbox ; i++, pbox++) { unsigned int x = pbox->x1; @@ -728,7 +728,7 @@ pbox->y2 > dev_priv->h) continue; - if ( flags & I810_FRONT ) { + if ( flags & I810_FRONT ) { BEGIN_LP_RING( 6 ); OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_COLOR_BLT | 0x3 ); @@ -768,8 +768,8 @@ static void i810_dma_dispatch_swap( drm_device_t *dev ) { - drm_i810_private_t *dev_priv = dev->dev_private; - drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; int nbox = sarea_priv->nbox; drm_clip_rect_t *pbox = sarea_priv->boxes; int pitch = dev_priv->pitch; @@ -779,10 +779,10 @@ DRM_DEBUG("swapbuffers\n"); - i810_kernel_lost_context(dev); + i810_kernel_lost_context(dev); - if (nbox > I810_NR_SAREA_CLIPRECTS) - nbox = I810_NR_SAREA_CLIPRECTS; + if (nbox > I810_NR_SAREA_CLIPRECTS) + nbox = I810_NR_SAREA_CLIPRECTS; for (i = 0 ; i < nbox; i++, pbox++) { @@ -820,19 +820,19 @@ int discard, int used) { - drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_buf_priv_t *buf_priv = buf->dev_private; - drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; - drm_clip_rect_t *box = sarea_priv->boxes; - int nbox = sarea_priv->nbox; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_clip_rect_t *box = sarea_priv->boxes; + int nbox = sarea_priv->nbox; unsigned long address = (unsigned long)buf->bus_address; unsigned long start = address - dev->agp->base; int i = 0; - RING_LOCALS; + RING_LOCALS; - i810_kernel_lost_context(dev); + i810_kernel_lost_context(dev); - if (nbox > I810_NR_SAREA_CLIPRECTS) + if (nbox > I810_NR_SAREA_CLIPRECTS) nbox = I810_NR_SAREA_CLIPRECTS; if (used > 4*1024) @@ -898,7 +898,7 @@ static void i810_dma_dispatch_flip( drm_device_t *dev ) { - drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_private_t *dev_priv = dev->dev_private; int pitch = dev_priv->pitch; RING_LOCALS; @@ -907,10 +907,10 @@ dev_priv->current_page, dev_priv->sarea_priv->pf_current_page); - i810_kernel_lost_context(dev); + i810_kernel_lost_context(dev); BEGIN_LP_RING( 2 ); - OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); + OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); OUT_RING( 0 ); ADVANCE_LP_RING(); @@ -945,44 +945,44 @@ void i810_dma_quiescent(drm_device_t *dev) { - drm_i810_private_t *dev_priv = dev->dev_private; - RING_LOCALS; + drm_i810_private_t *dev_priv = dev->dev_private; + RING_LOCALS; -/* printk("%s\n", __FUNCTION__); */ +/* printk("%s\n", __FUNCTION__); */ - i810_kernel_lost_context(dev); + i810_kernel_lost_context(dev); - BEGIN_LP_RING(4); - OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); - OUT_RING( CMD_REPORT_HEAD ); - OUT_RING( 0 ); - OUT_RING( 0 ); - ADVANCE_LP_RING(); + BEGIN_LP_RING(4); + OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( 0 ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); i810_wait_ring( dev, dev_priv->ring.Size - 8 ); } static int i810_flush_queue(drm_device_t *dev) { - drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_private_t *dev_priv = dev->dev_private; drm_device_dma_t *dma = dev->dma; - int i, ret = 0; - RING_LOCALS; + int i, ret = 0; + RING_LOCALS; -/* printk("%s\n", __FUNCTION__); */ +/* printk("%s\n", __FUNCTION__); */ - i810_kernel_lost_context(dev); + i810_kernel_lost_context(dev); - BEGIN_LP_RING(2); - OUT_RING( CMD_REPORT_HEAD ); - OUT_RING( 0 ); - ADVANCE_LP_RING(); + BEGIN_LP_RING(2); + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); i810_wait_ring( dev, dev_priv->ring.Size - 8 ); - for (i = 0; i < dma->buf_count; i++) { - drm_buf_t *buf = dma->buflist[ i ]; - drm_i810_buf_priv_t *buf_priv = buf->dev_private; + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE, I810_BUF_FREE); @@ -993,7 +993,7 @@ DRM_DEBUG("still on client\n"); } - return ret; + return ret; } /* Must be called with the lock held */ @@ -1005,14 +1005,14 @@ int i; if (!dma) return; - if (!dev->dev_private) return; + if (!dev->dev_private) return; if (!dma->buflist) return; - i810_flush_queue(dev); + i810_flush_queue(dev); for (i = 0; i < dma->buf_count; i++) { - drm_buf_t *buf = dma->buflist[ i ]; - drm_i810_buf_priv_t *buf_priv = buf->dev_private; + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; if (buf->filp == filp && buf_priv) { int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, @@ -1021,7 +1021,7 @@ if (used == I810_BUF_CLIENT) DRM_DEBUG("reclaimed from client\n"); if (buf_priv->currently_mapped == I810_BUF_MAPPED) - buf_priv->currently_mapped = I810_BUF_UNMAPPED; + buf_priv->currently_mapped = I810_BUF_UNMAPPED; } } } @@ -1029,16 +1029,16 @@ int i810_flush_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i810_flush_ioctl called without lock held\n"); return -EINVAL; } - i810_flush_queue(dev); - return 0; + i810_flush_queue(dev); + return 0; } @@ -1048,10 +1048,10 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_device_dma_t *dma = dev->dma; - drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; - u32 *hw_status = dev_priv->hw_status_page; - drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) - dev_priv->sarea_priv; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; drm_i810_vertex_t vertex; if (copy_from_user(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex))) @@ -1072,10 +1072,10 @@ dma->buflist[ vertex.idx ], vertex.discard, vertex.used ); - atomic_add(vertex.used, &dev->counts[_DRM_STAT_SECONDARY]); + atomic_add(vertex.used, &dev->counts[_DRM_STAT_SECONDARY]); atomic_inc(&dev->counts[_DRM_STAT_DMA]); sarea_priv->last_enqueue = dev_priv->counter-1; - sarea_priv->last_dispatch = (int) hw_status[5]; + sarea_priv->last_dispatch = (int) hw_status[5]; return 0; } @@ -1089,7 +1089,7 @@ drm_device_t *dev = priv->dev; drm_i810_clear_t clear; - if (copy_from_user(&clear, (drm_i810_clear_t *)arg, sizeof(clear))) + if (copy_from_user(&clear, (drm_i810_clear_t *)arg, sizeof(clear))) return -EFAULT; if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { @@ -1097,15 +1097,15 @@ return -EINVAL; } - /* GH: Someone's doing nasty things... */ - if (!dev->dev_private) { - return -EINVAL; - } + /* GH: Someone's doing nasty things... */ + if (!dev->dev_private) { + return -EINVAL; + } i810_dma_dispatch_clear( dev, clear.flags, clear.clear_color, clear.clear_depth ); - return 0; + return 0; } int i810_swap_bufs(struct inode *inode, struct file *filp, @@ -1122,20 +1122,20 @@ } i810_dma_dispatch_swap( dev ); - return 0; + return 0; } int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - drm_file_t *priv = filp->private_data; + drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; - drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; - u32 *hw_status = dev_priv->hw_status_page; - drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) - dev_priv->sarea_priv; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; - sarea_priv->last_dispatch = (int) hw_status[5]; + sarea_priv->last_dispatch = (int) hw_status[5]; return 0; } @@ -1146,12 +1146,12 @@ drm_device_t *dev = priv->dev; int retcode = 0; drm_i810_dma_t d; - drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; - u32 *hw_status = dev_priv->hw_status_page; - drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) - dev_priv->sarea_priv; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; - if (copy_from_user(&d, (drm_i810_dma_t *)arg, sizeof(d))) + if (copy_from_user(&d, (drm_i810_dma_t *)arg, sizeof(d))) return -EFAULT; if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { @@ -1168,7 +1168,7 @@ if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d))) return -EFAULT; - sarea_priv->last_dispatch = (int) hw_status[5]; + sarea_priv->last_dispatch = (int) hw_status[5]; return retcode; } @@ -1384,5 +1384,5 @@ i810_do_init_pageflip( dev ); i810_dma_dispatch_flip( dev ); - return 0; + return 0; } --- diff/drivers/char/drm/i830.h 2003-05-21 11:50:14.000000000 +0100 +++ source/drivers/char/drm/i830.h 2004-02-09 10:39:52.000000000 +0000 @@ -77,6 +77,13 @@ [DRM_IOCTL_NR(DRM_IOCTL_I830_GETPARAM)] = { i830_getparam, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_I830_SETPARAM)] = { i830_setparam, 1, 0 } +#define DRIVER_PCI_IDS \ + {0x8086, 0x3577, 0, "Intel i830M GMCH"}, \ + {0x8086, 0x2562, 0, "Intel i845G GMCH"}, \ + {0x8086, 0x3582, 0, "Intel i852GM/i855GM GMCH"}, \ + {0x8086, 0x2572, 0, "Intel i865G GMCH"}, \ + {0, 0, 0, NULL} + #define __HAVE_COUNTERS 4 #define __HAVE_COUNTER6 _DRM_STAT_IRQ #define __HAVE_COUNTER7 _DRM_STAT_PRIMARY @@ -115,10 +122,10 @@ #define USE_IRQS 0 #if USE_IRQS -#define __HAVE_DMA_IRQ 1 +#define __HAVE_IRQ 1 #define __HAVE_SHARED_IRQ 1 #else -#define __HAVE_DMA_IRQ 0 +#define __HAVE_IRQ 0 #endif --- diff/drivers/char/drm/i830_dma.c 2003-06-09 14:18:18.000000000 +0100 +++ source/drivers/char/drm/i830_dma.c 2004-02-09 10:39:52.000000000 +0000 @@ -231,12 +231,12 @@ { drm_device_dma_t *dma = dev->dma; -#if _HAVE_DMA_IRQ +#if __HAVE_IRQ /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. */ - if (dev->irq) DRM(irq_uninstall)(dev); + if (dev->irq_enabled) DRM(irq_uninstall)(dev); #endif if (dev->dev_private) { @@ -1539,7 +1539,7 @@ switch( param.param ) { case I830_PARAM_IRQ_ACTIVE: - value = dev->irq ? 1 : 0; + value = dev->irq_enabled; break; default: return -EINVAL; --- diff/drivers/char/drm/i830_drv.c 2003-05-21 11:50:14.000000000 +0100 +++ source/drivers/char/drm/i830_drv.c 2004-02-09 10:39:52.000000000 +0000 @@ -50,6 +50,7 @@ #include "drm_fops.h" #include "drm_init.h" #include "drm_ioctl.h" +#include "drm_irq.h" #include "drm_lock.h" #include "drm_memory.h" #include "drm_proc.h" --- diff/drivers/char/drm/i830_irq.c 2003-09-30 15:46:12.000000000 +0100 +++ source/drivers/char/drm/i830_irq.c 2004-02-09 10:39:52.000000000 +0000 @@ -35,7 +35,7 @@ #include -irqreturn_t DRM(dma_service)( DRM_IRQ_ARGS ) +irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *)arg; drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; --- diff/drivers/char/drm/mga.h 2003-05-21 11:50:14.000000000 +0100 +++ source/drivers/char/drm/mga.h 2004-02-09 10:39:52.000000000 +0000 @@ -64,6 +64,12 @@ [DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)] = { mga_dma_blit, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_MGA_GETPARAM)]= { mga_getparam, 1, 0 }, +#define DRIVER_PCI_IDS \ + {0x102b, 0x0521, 0, "Matrox G200 (AGP)"}, \ + {0x102b, 0x0525, 0, "Matrox G400/G450 (AGP)"}, \ + {0x102b, 0x2527, 0, "Matrox G550 (AGP)"}, \ + {0, 0, 0, NULL} + #define __HAVE_COUNTERS 3 #define __HAVE_COUNTER6 _DRM_STAT_IRQ #define __HAVE_COUNTER7 _DRM_STAT_PRIMARY @@ -78,7 +84,7 @@ /* DMA customization: */ #define __HAVE_DMA 1 -#define __HAVE_DMA_IRQ 1 +#define __HAVE_IRQ 1 #define __HAVE_VBL_IRQ 1 #define __HAVE_SHARED_IRQ 1 --- diff/drivers/char/drm/mga_dma.c 2003-06-09 14:18:18.000000000 +0100 +++ source/drivers/char/drm/mga_dma.c 2004-02-09 10:39:52.000000000 +0000 @@ -500,14 +500,6 @@ return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->fb, init->fb_offset ); - if(!dev_priv->fb) { - DRM_ERROR( "failed to find framebuffer!\n" ); - /* Assign dev_private so we can do cleanup. */ - dev->dev_private = (void *)dev_priv; - mga_do_cleanup_dma( dev ); - return DRM_ERR(EINVAL); - } DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); if(!dev_priv->mmio) { DRM_ERROR( "failed to find mmio region!\n" ); @@ -639,12 +631,12 @@ { DRM_DEBUG( "\n" ); -#if _HAVE_DMA_IRQ +#if __HAVE_IRQ /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. */ - if ( dev->irq ) DRM(irq_uninstall)(dev); + if ( dev->irq_enabled ) DRM(irq_uninstall)(dev); #endif if ( dev->dev_private ) { --- diff/drivers/char/drm/mga_drv.c 2002-10-16 04:27:56.000000000 +0100 +++ source/drivers/char/drm/mga_drv.c 2004-02-09 10:39:52.000000000 +0000 @@ -45,6 +45,7 @@ #include "drm_fops.h" #include "drm_init.h" #include "drm_ioctl.h" +#include "drm_irq.h" #include "drm_lock.h" #include "drm_memory.h" #include "drm_proc.h" --- diff/drivers/char/drm/mga_drv.h 2003-06-09 14:18:18.000000000 +0100 +++ source/drivers/char/drm/mga_drv.h 2004-02-09 10:39:52.000000000 +0000 @@ -91,7 +91,6 @@ unsigned int texture_size; drm_local_map_t *sarea; - drm_local_map_t *fb; drm_local_map_t *mmio; drm_local_map_t *status; drm_local_map_t *warp; --- diff/drivers/char/drm/mga_irq.c 2003-05-21 11:50:14.000000000 +0100 +++ source/drivers/char/drm/mga_irq.c 2004-02-09 10:39:52.000000000 +0000 @@ -36,7 +36,7 @@ #include "mga_drm.h" #include "mga_drv.h" -irqreturn_t mga_dma_service( DRM_IRQ_ARGS ) +irqreturn_t mga_irq_handler( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *) arg; drm_mga_private_t *dev_priv = --- diff/drivers/char/drm/r128.h 2003-08-26 10:00:52.000000000 +0100 +++ source/drivers/char/drm/r128.h 2004-02-09 10:39:52.000000000 +0000 @@ -79,6 +79,46 @@ [DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)] = { r128_cce_indirect, 1, 1 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_GETPARAM)] = { r128_getparam, 1, 0 }, +#define DRIVER_PCI_IDS \ + {0x1002, 0x4c45, 0, "ATI Rage 128 Mobility LE (PCI)"}, \ + {0x1002, 0x4c46, 0, "ATI Rage 128 Mobility LF (AGP)"}, \ + {0x1002, 0x4d46, 0, "ATI Rage 128 Mobility MF (AGP)"}, \ + {0x1002, 0x4d4c, 0, "ATI Rage 128 Mobility ML (AGP)"}, \ + {0x1002, 0x5041, 0, "ATI Rage 128 Pro PA (PCI)"}, \ + {0x1002, 0x5042, 0, "ATI Rage 128 Pro PB (AGP)"}, \ + {0x1002, 0x5043, 0, "ATI Rage 128 Pro PC (AGP)"}, \ + {0x1002, 0x5044, 0, "ATI Rage 128 Pro PD (PCI)"}, \ + {0x1002, 0x5045, 0, "ATI Rage 128 Pro PE (AGP)"}, \ + {0x1002, 0x5046, 0, "ATI Rage 128 Pro PF (AGP)"}, \ + {0x1002, 0x5047, 0, "ATI Rage 128 Pro PG (PCI)"}, \ + {0x1002, 0x5048, 0, "ATI Rage 128 Pro PH (AGP)"}, \ + {0x1002, 0x5049, 0, "ATI Rage 128 Pro PI (AGP)"}, \ + {0x1002, 0x504A, 0, "ATI Rage 128 Pro PJ (PCI)"}, \ + {0x1002, 0x504B, 0, "ATI Rage 128 Pro PK (AGP)"}, \ + {0x1002, 0x504C, 0, "ATI Rage 128 Pro PL (AGP)"}, \ + {0x1002, 0x504D, 0, "ATI Rage 128 Pro PM (PCI)"}, \ + {0x1002, 0x504E, 0, "ATI Rage 128 Pro PN (AGP)"}, \ + {0x1002, 0x504F, 0, "ATI Rage 128 Pro PO (AGP)"}, \ + {0x1002, 0x5050, 0, "ATI Rage 128 Pro PP (PCI)"}, \ + {0x1002, 0x5051, 0, "ATI Rage 128 Pro PQ (AGP)"}, \ + {0x1002, 0x5052, 0, "ATI Rage 128 Pro PR (PCI)"}, \ + {0x1002, 0x5053, 0, "ATI Rage 128 Pro PS (PCI)"}, \ + {0x1002, 0x5054, 0, "ATI Rage 128 Pro PT (AGP)"}, \ + {0x1002, 0x5055, 0, "ATI Rage 128 Pro PU (AGP)"}, \ + {0x1002, 0x5056, 0, "ATI Rage 128 Pro PV (PCI)"}, \ + {0x1002, 0x5057, 0, "ATI Rage 128 Pro PW (AGP)"}, \ + {0x1002, 0x5058, 0, "ATI Rage 128 Pro PX (AGP)"}, \ + {0x1002, 0x5245, 0, "ATI Rage 128 RE (PCI)"}, \ + {0x1002, 0x5246, 0, "ATI Rage 128 RF (AGP)"}, \ + {0x1002, 0x5247, 0, "ATI Rage 128 RG (AGP)"}, \ + {0x1002, 0x524b, 0, "ATI Rage 128 RK (PCI)"}, \ + {0x1002, 0x524c, 0, "ATI Rage 128 RL (AGP)"}, \ + {0x1002, 0x534d, 0, "ATI Rage 128 SM (AGP)"}, \ + {0x1002, 0x5446, 0, "ATI Rage 128 Pro Ultra TF (AGP)"}, \ + {0x1002, 0x544C, 0, "ATI Rage 128 Pro Ultra TL (AGP)"}, \ + {0x1002, 0x5452, 0, "ATI Rage 128 Pro Ultra TR (AGP)"}, \ + {0, 0, 0, NULL} + /* Driver customization: */ #define DRIVER_PRERELEASE() do { \ @@ -97,7 +137,7 @@ /* DMA customization: */ #define __HAVE_DMA 1 -#define __HAVE_DMA_IRQ 1 +#define __HAVE_IRQ 1 #define __HAVE_VBL_IRQ 1 #define __HAVE_SHARED_IRQ 1 --- diff/drivers/char/drm/r128_cce.c 2003-09-30 15:46:12.000000000 +0100 +++ source/drivers/char/drm/r128_cce.c 2004-02-09 10:39:52.000000000 +0000 @@ -212,7 +212,7 @@ int i; for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { - if ( GET_RING_HEAD( &dev_priv->ring ) == dev_priv->ring.tail ) { + if ( GET_RING_HEAD( dev_priv ) == dev_priv->ring.tail ) { int pm4stat = R128_READ( R128_PM4_STAT ); if ( ( (pm4stat & R128_PM4_FIFOCNT_MASK) >= dev_priv->cce_fifo_size ) && @@ -238,7 +238,8 @@ r128_do_wait_for_idle( dev_priv ); R128_WRITE( R128_PM4_BUFFER_CNTL, - dev_priv->cce_mode | dev_priv->ring.size_l2qw ); + dev_priv->cce_mode | dev_priv->ring.size_l2qw + | R128_PM4_BUFFER_CNTL_NOUPDATE ); R128_READ( R128_PM4_BUFFER_ADDR ); /* as per the sample code */ R128_WRITE( R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN ); @@ -253,7 +254,6 @@ { R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 ); R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 ); - SET_RING_HEAD( &dev_priv->ring, 0 ); dev_priv->ring.tail = 0; } @@ -264,7 +264,8 @@ static void r128_do_cce_stop( drm_r128_private_t *dev_priv ) { R128_WRITE( R128_PM4_MICRO_CNTL, 0 ); - R128_WRITE( R128_PM4_BUFFER_CNTL, R128_PM4_NONPM4 ); + R128_WRITE( R128_PM4_BUFFER_CNTL, + R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE ); dev_priv->cce_running = 0; } @@ -333,26 +334,6 @@ R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 ); R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 ); - /* DL_RPTR_ADDR is a physical address in AGP space. */ - SET_RING_HEAD( &dev_priv->ring, 0 ); - - if ( !dev_priv->is_pci ) { - R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, - dev_priv->ring_rptr->offset ); - } else { - drm_sg_mem_t *entry = dev->sg; - unsigned long tmp_ofs, page_ofs; - - tmp_ofs = dev_priv->ring_rptr->offset - dev->sg->handle; - page_ofs = tmp_ofs >> PAGE_SHIFT; - - R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, - entry->busaddr[page_ofs]); - DRM_DEBUG( "ring rptr: offset=0x%08lx handle=0x%08lx\n", - (unsigned long) entry->busaddr[page_ofs], - entry->handle + tmp_ofs ); - } - /* Set watermark control */ R128_WRITE( R128_PM4_BUFFER_WM_CNTL, ((R128_WATERMARK_L/4) << R128_WMA_SHIFT) @@ -486,13 +467,6 @@ return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->fb, init->fb_offset ); - if(!dev_priv->fb) { - DRM_ERROR("could not find framebuffer!\n"); - dev->dev_private = (void *)dev_priv; - r128_do_cleanup_cce( dev ); - return DRM_ERR(EINVAL); - } DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); if(!dev_priv->mmio) { DRM_ERROR("could not find mmio region!\n"); @@ -567,9 +541,6 @@ #endif dev_priv->cce_buffers_offset = dev->sg->handle; - dev_priv->ring.head = ((__volatile__ u32 *) - dev_priv->ring_rptr->handle); - dev_priv->ring.start = (u32 *)dev_priv->cce_ring->handle; dev_priv->ring.end = ((u32 *)dev_priv->cce_ring->handle + init->ring_size / sizeof(u32)); @@ -580,7 +551,6 @@ (dev_priv->ring.size / sizeof(u32)) - 1; dev_priv->ring.high_mark = 128; - dev_priv->ring.ring_rptr = dev_priv->ring_rptr; dev_priv->sarea_priv->last_frame = 0; R128_WRITE( R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame ); @@ -589,8 +559,9 @@ R128_WRITE( R128_LAST_DISPATCH_REG, dev_priv->sarea_priv->last_dispatch ); -#if __REALLY_HAVE_SG +#if __REALLY_HAVE_AGP if ( dev_priv->is_pci ) { +#endif if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart, &dev_priv->bus_pci_gart) ) { DRM_ERROR( "failed to init PCI GART!\n" ); @@ -599,6 +570,7 @@ return DRM_ERR(ENOMEM); } R128_WRITE( R128_PCI_GART_PAGE, dev_priv->bus_pci_gart ); +#if __REALLY_HAVE_AGP } #endif @@ -615,12 +587,12 @@ int r128_do_cleanup_cce( drm_device_t *dev ) { -#if _HAVE_DMA_IRQ +#if __HAVE_IRQ /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. */ - if ( dev->irq ) DRM(irq_uninstall)(dev); + if ( dev->irq_enabled ) DRM(irq_uninstall)(dev); #endif if ( dev->dev_private ) { @@ -901,7 +873,7 @@ int i; for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { - r128_update_ring_snapshot( ring ); + r128_update_ring_snapshot( dev_priv ); if ( ring->space >= n ) return 0; DRM_UDELAY( 1 ); --- diff/drivers/char/drm/r128_drv.c 2002-10-16 04:27:48.000000000 +0100 +++ source/drivers/char/drm/r128_drv.c 2004-02-09 10:39:52.000000000 +0000 @@ -47,6 +47,7 @@ #include "drm_fops.h" #include "drm_init.h" #include "drm_ioctl.h" +#include "drm_irq.h" #include "drm_lock.h" #include "drm_memory.h" #include "drm_proc.h" --- diff/drivers/char/drm/r128_drv.h 2003-08-20 14:16:27.000000000 +0100 +++ source/drivers/char/drm/r128_drv.h 2004-02-09 10:39:52.000000000 +0000 @@ -34,8 +34,7 @@ #ifndef __R128_DRV_H__ #define __R128_DRV_H__ -#define GET_RING_HEAD(ring) DRM_READ32( (ring)->ring_rptr, 0 ) /* (ring)->head */ -#define SET_RING_HEAD(ring,val) DRM_WRITE32( (ring)->ring_rptr, 0, (val) ) /* (ring)->head */ +#define GET_RING_HEAD(dev_priv) R128_READ( R128_PM4_BUFFER_DL_RPTR ) typedef struct drm_r128_freelist { unsigned int age; @@ -50,13 +49,11 @@ int size; int size_l2qw; - volatile u32 *head; u32 tail; u32 tail_mask; int space; int high_mark; - drm_local_map_t *ring_rptr; } drm_r128_ring_buffer_t; typedef struct drm_r128_private { @@ -100,7 +97,6 @@ u32 span_pitch_offset_c; drm_local_map_t *sarea; - drm_local_map_t *fb; drm_local_map_t *mmio; drm_local_map_t *cce_ring; drm_local_map_t *ring_rptr; @@ -132,14 +128,6 @@ extern int r128_wait_ring( drm_r128_private_t *dev_priv, int n ); -static __inline__ void -r128_update_ring_snapshot( drm_r128_ring_buffer_t *ring ) -{ - ring->space = (GET_RING_HEAD( ring ) - ring->tail) * sizeof(u32); - if ( ring->space <= 0 ) - ring->space += ring->size; -} - extern int r128_do_cce_idle( drm_r128_private_t *dev_priv ); extern int r128_do_cleanup_cce( drm_device_t *dev ); extern int r128_do_cleanup_pageflip( drm_device_t *dev ); @@ -279,6 +267,7 @@ # define R128_PM4_64PIO_64VCBM_64INDBM (7 << 28) # define R128_PM4_64BM_64VCBM_64INDBM (8 << 28) # define R128_PM4_64PIO_64VCPIO_64INDPIO (15 << 28) +# define R128_PM4_BUFFER_CNTL_NOUPDATE (1 << 27) #define R128_PM4_BUFFER_WM_CNTL 0x0708 # define R128_WMA_SHIFT 0 @@ -403,6 +392,15 @@ (pkt) | ((n) << 16)) +static __inline__ void +r128_update_ring_snapshot( drm_r128_private_t *dev_priv ) +{ + drm_r128_ring_buffer_t *ring = &dev_priv->ring; + ring->space = (GET_RING_HEAD( dev_priv ) - ring->tail) * sizeof(u32); + if ( ring->space <= 0 ) + ring->space += ring->size; +} + /* ================================================================ * Misc helper macros */ @@ -412,7 +410,7 @@ drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i; \ if ( ring->space < ring->high_mark ) { \ for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { \ - r128_update_ring_snapshot( ring ); \ + r128_update_ring_snapshot( dev_priv ); \ if ( ring->space >= ring->high_mark ) \ goto __ring_space_done; \ DRM_UDELAY(1); \ @@ -445,17 +443,10 @@ * Ring control */ -#if defined(__powerpc__) -#define r128_flush_write_combine() (void) GET_RING_HEAD( &dev_priv->ring ) -#else -#define r128_flush_write_combine() DRM_WRITEMEMORYBARRIER() -#endif - - #define R128_VERBOSE 0 #define RING_LOCALS \ - int write; unsigned int tail_mask; volatile u32 *ring; + int write, _nr; unsigned int tail_mask; volatile u32 *ring; #define BEGIN_RING( n ) do { \ if ( R128_VERBOSE ) { \ @@ -463,9 +454,10 @@ (n), __FUNCTION__ ); \ } \ if ( dev_priv->ring.space <= (n) * sizeof(u32) ) { \ + COMMIT_RING(); \ r128_wait_ring( dev_priv, (n) * sizeof(u32) ); \ } \ - dev_priv->ring.space -= (n) * sizeof(u32); \ + _nr = n; dev_priv->ring.space -= (n) * sizeof(u32); \ ring = dev_priv->ring.start; \ write = dev_priv->ring.tail; \ tail_mask = dev_priv->ring.tail_mask; \ @@ -488,9 +480,23 @@ dev_priv->ring.start, \ write * sizeof(u32) ); \ } \ - r128_flush_write_combine(); \ - dev_priv->ring.tail = write; \ - R128_WRITE( R128_PM4_BUFFER_DL_WPTR, write ); \ + if (((dev_priv->ring.tail + _nr) & tail_mask) != write) { \ + DRM_ERROR( \ + "ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n", \ + ((dev_priv->ring.tail + _nr) & tail_mask), \ + write, __LINE__); \ + } else \ + dev_priv->ring.tail = write; \ +} while (0) + +#define COMMIT_RING() do { \ + if ( R128_VERBOSE ) { \ + DRM_INFO( "COMMIT_RING() tail=0x%06x\n", \ + dev_priv->ring.tail ); \ + } \ + DRM_MEMORYBARRIER(); \ + R128_WRITE( R128_PM4_BUFFER_DL_WPTR, dev_priv->ring.tail ); \ + R128_READ( R128_PM4_BUFFER_DL_WPTR ); \ } while (0) #define OUT_RING( x ) do { \ --- diff/drivers/char/drm/r128_irq.c 2003-05-21 11:50:14.000000000 +0100 +++ source/drivers/char/drm/r128_irq.c 2004-02-09 10:39:52.000000000 +0000 @@ -36,7 +36,7 @@ #include "r128_drm.h" #include "r128_drv.h" -irqreturn_t r128_dma_service( DRM_IRQ_ARGS ) +irqreturn_t r128_irq_handler( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *) arg; drm_r128_private_t *dev_priv = --- diff/drivers/char/drm/r128_state.c 2003-08-20 14:16:27.000000000 +0100 +++ source/drivers/char/drm/r128_state.c 2004-02-09 10:39:52.000000000 +0000 @@ -45,7 +45,7 @@ RING_LOCALS; DRM_DEBUG( " %s\n", __FUNCTION__ ); - BEGIN_RING( 17 ); + BEGIN_RING( (count < 3? count: 3) * 5 + 2 ); if ( count >= 1 ) { OUT_RING( CCE_PACKET0( R128_AUX1_SC_LEFT, 3 ) ); @@ -1269,6 +1269,7 @@ sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS; r128_cce_dispatch_clear( dev, &clear ); + COMMIT_RING(); /* Make sure we restore the 3D state next time. */ @@ -1304,8 +1305,10 @@ R128_WRITE( R128_CRTC_OFFSET, dev_priv->crtc_offset ); R128_WRITE( R128_CRTC_OFFSET_CNTL, dev_priv->crtc_offset_cntl ); - if (dev_priv->current_page != 0) + if (dev_priv->current_page != 0) { r128_cce_dispatch_flip( dev ); + COMMIT_RING(); + } dev_priv->page_flipping = 0; return 0; @@ -1330,6 +1333,7 @@ r128_cce_dispatch_flip( dev ); + COMMIT_RING(); return 0; } @@ -1351,6 +1355,7 @@ dev_priv->sarea_priv->dirty |= (R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS); + COMMIT_RING(); return 0; } @@ -1410,6 +1415,7 @@ r128_cce_dispatch_vertex( dev, buf ); + COMMIT_RING(); return 0; } @@ -1481,6 +1487,7 @@ r128_cce_dispatch_indices( dev, buf, elts.start, elts.end, count ); + COMMIT_RING(); return 0; } @@ -1490,6 +1497,7 @@ drm_device_dma_t *dma = dev->dma; drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_blit_t blit; + int ret; LOCK_TEST_WITH_RETURN( dev, filp ); @@ -1507,7 +1515,10 @@ RING_SPACE_TEST_WITH_RETURN( dev_priv ); VB_AGE_TEST_WITH_RETURN( dev_priv ); - return r128_cce_dispatch_blit( filp, dev, &blit ); + ret = r128_cce_dispatch_blit( filp, dev, &blit ); + + COMMIT_RING(); + return ret; } int r128_cce_depth( DRM_IOCTL_ARGS ) @@ -1515,6 +1526,7 @@ DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_depth_t depth; + int ret; LOCK_TEST_WITH_RETURN( dev, filp ); @@ -1523,18 +1535,20 @@ RING_SPACE_TEST_WITH_RETURN( dev_priv ); + ret = DRM_ERR(EINVAL); switch ( depth.func ) { case R128_WRITE_SPAN: - return r128_cce_dispatch_write_span( dev, &depth ); + ret = r128_cce_dispatch_write_span( dev, &depth ); case R128_WRITE_PIXELS: - return r128_cce_dispatch_write_pixels( dev, &depth ); + ret = r128_cce_dispatch_write_pixels( dev, &depth ); case R128_READ_SPAN: - return r128_cce_dispatch_read_span( dev, &depth ); + ret = r128_cce_dispatch_read_span( dev, &depth ); case R128_READ_PIXELS: - return r128_cce_dispatch_read_pixels( dev, &depth ); + ret = r128_cce_dispatch_read_pixels( dev, &depth ); } - return DRM_ERR(EINVAL); + COMMIT_RING(); + return ret; } int r128_cce_stipple( DRM_IOCTL_ARGS ) @@ -1557,6 +1571,7 @@ r128_cce_dispatch_stipple( dev, mask ); + COMMIT_RING(); return 0; } @@ -1632,6 +1647,7 @@ */ r128_cce_dispatch_indirect( dev, buf, indirect.start, indirect.end ); + COMMIT_RING(); return 0; } --- diff/drivers/char/drm/radeon.h 2003-09-30 15:46:12.000000000 +0100 +++ source/drivers/char/drm/radeon.h 2004-02-09 10:39:52.000000000 +0000 @@ -51,7 +51,7 @@ #define DRIVER_DATE "20020828" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 9 +#define DRIVER_MINOR 10 #define DRIVER_PATCHLEVEL 0 /* Interface history: @@ -81,6 +81,9 @@ * Add 'GET' queries for starting additional clients on different VT's. * 1.9 - Add DRM_IOCTL_RADEON_CP_RESUME ioctl. * Add texture rectangle support for r100. + * 1.10- Add SETPARAM ioctl; first parameter to set is FB_LOCATION, which + * clients use to tell the DRM where they think the framebuffer is + * located in the card's address space */ #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \ @@ -106,10 +109,82 @@ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_ALLOC)] = { radeon_mem_alloc, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_FREE)] = { radeon_mem_free, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INIT_HEAP)] = { radeon_mem_init_heap, 1, 1 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)] = { radeon_irq_emit, 1, 0 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)] = { radeon_irq_emit, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SETPARAM)] = { radeon_cp_setparam, 1, 0 }, \ + +#define DRIVER_PCI_IDS \ + {0x1002, 0x4136, 0, "ATI Radeon RS100 IGP 320M"}, \ + {0x1002, 0x4137, 0, "ATI Radeon RS200 IGP"}, \ + {0x1002, 0x4237, 0, "ATI Radeon RS250 IGP"}, \ + {0x1002, 0x4242, 0, "ATI Radeon BB R200 AIW 8500DV"}, \ + {0x1002, 0x4242, 0, "ATI Radeon BC R200"}, \ + {0x1002, 0x4336, 0, "ATI Radeon RS100 Mobility U1"}, \ + {0x1002, 0x4337, 0, "ATI Radeon RS200 Mobility IGP 340M"}, \ + {0x1002, 0x4437, 0, "ATI Radeon RS250 Mobility IGP"}, \ + {0x1002, 0x4964, 0, "ATI Radeon Id R250 9000"}, \ + {0x1002, 0x4965, 0, "ATI Radeon Ie R250 9000"}, \ + {0x1002, 0x4966, 0, "ATI Radeon If R250 9000"}, \ + {0x1002, 0x4967, 0, "ATI Radeon Ig R250 9000"}, \ + {0x1002, 0x4C57, 0, "ATI Radeon LW Mobility 7500 M7"}, \ + {0x1002, 0x4C58, 0, "ATI Radeon LX RV200 Mobility FireGL 7800 M7"}, \ + {0x1002, 0x4C59, 0, "ATI Radeon LY Mobility M6"}, \ + {0x1002, 0x4C5A, 0, "ATI Radeon LZ Mobility M6"}, \ + {0x1002, 0x4C64, 0, "ATI Radeon Ld R250 Mobility 9000 M9"}, \ + {0x1002, 0x4C65, 0, "ATI Radeon Le R250 Mobility 9000 M9"}, \ + {0x1002, 0x4C66, 0, "ATI Radeon Lf R250 Mobility 9000 M9"}, \ + {0x1002, 0x4C67, 0, "ATI Radeon Lg R250 Mobility 9000 M9"}, \ + {0x1002, 0x5144, 0, "ATI Radeon QD R100"}, \ + {0x1002, 0x5145, 0, "ATI Radeon QE R100"}, \ + {0x1002, 0x5146, 0, "ATI Radeon QF R100"}, \ + {0x1002, 0x5147, 0, "ATI Radeon QG R100"}, \ + {0x1002, 0x5148, 0, "ATI Radeon QH R200 8500"}, \ + {0x1002, 0x5149, 0, "ATI Radeon QI R200"}, \ + {0x1002, 0x514A, 0, "ATI Radeon QJ R200"}, \ + {0x1002, 0x514B, 0, "ATI Radeon QK R200"}, \ + {0x1002, 0x514C, 0, "ATI Radeon QL R200 8500 LE"}, \ + {0x1002, 0x514D, 0, "ATI Radeon QM R200 9100"}, \ + {0x1002, 0x514E, 0, "ATI Radeon QN R200 8500 LE"}, \ + {0x1002, 0x514F, 0, "ATI Radeon QO R200 8500 LE"}, \ + {0x1002, 0x5157, 0, "ATI Radeon QW RV200 7500"}, \ + {0x1002, 0x5158, 0, "ATI Radeon QX RV200 7500"}, \ + {0x1002, 0x5159, 0, "ATI Radeon QY RV100 7000/VE"}, \ + {0x1002, 0x515A, 0, "ATI Radeon QZ RV100 7000/VE"}, \ + {0x1002, 0x5168, 0, "ATI Radeon Qh R200"}, \ + {0x1002, 0x5169, 0, "ATI Radeon Qi R200"}, \ + {0x1002, 0x516A, 0, "ATI Radeon Qj R200"}, \ + {0x1002, 0x516B, 0, "ATI Radeon Qk R200"}, \ + {0x1002, 0x516C, 0, "ATI Radeon Ql R200"}, \ + {0x1002, 0x5834, 0, "ATI Radeon RS300 IGP"}, \ + {0x1002, 0x5835, 0, "ATI Radeon RS300 Mobility IGP"}, \ + {0x1002, 0x5836, 0, "ATI Radeon RS300 IGP"}, \ + {0x1002, 0x5837, 0, "ATI Radeon RS300 IGP"}, \ + {0x1002, 0x5960, 0, "ATI Radeon RV280 9200"}, \ + {0x1002, 0x5961, 0, "ATI Radeon RV280 9200 SE"}, \ + {0x1002, 0x5962, 0, "ATI Radeon RV280 9200"}, \ + {0x1002, 0x5963, 0, "ATI Radeon RV280 9200"}, \ + {0x1002, 0x5964, 0, "ATI Radeon RV280 9200 SE"}, \ + {0x1002, 0x5968, 0, "ATI Radeon RV280 9200"}, \ + {0x1002, 0x5969, 0, "ATI Radeon RV280 9200"}, \ + {0x1002, 0x596A, 0, "ATI Radeon RV280 9200"}, \ + {0x1002, 0x596B, 0, "ATI Radeon RV280 9200"}, \ + {0x1002, 0x5c61, 0, "ATI Radeon RV280 Mobility"}, \ + {0x1002, 0x5c62, 0, "ATI Radeon RV280"}, \ + {0x1002, 0x5c63, 0, "ATI Radeon RV280 Mobility"}, \ + {0x1002, 0x5c64, 0, "ATI Radeon RV280"}, \ + {0, 0, 0, NULL} +#define DRIVER_FILE_FIELDS \ + int64_t radeon_fb_delta; \ +#define DRIVER_OPEN_HELPER( filp_priv, dev ) \ +do { \ + drm_radeon_private_t *dev_priv = dev->dev_private; \ + if ( dev_priv ) \ + filp_priv->radeon_fb_delta = dev_priv->fb_location; \ + else \ + filp_priv->radeon_fb_delta = 0; \ +} while( 0 ) /* When a client dies: * - Check for and clean up flipped page state @@ -125,7 +200,7 @@ radeon_do_cleanup_pageflip( dev ); \ } \ radeon_mem_release( filp, dev_priv->gart_heap ); \ - radeon_mem_release( filp, dev_priv->fb_heap ); \ + radeon_mem_release( filp, dev_priv->fb_heap ); \ } \ } while (0) @@ -142,7 +217,7 @@ /* DMA customization: */ #define __HAVE_DMA 1 -#define __HAVE_DMA_IRQ 1 +#define __HAVE_IRQ 1 #define __HAVE_VBL_IRQ 1 #define __HAVE_SHARED_IRQ 1 --- diff/drivers/char/drm/radeon_cp.c 2003-09-30 15:46:12.000000000 +0100 +++ source/drivers/char/drm/radeon_cp.c 2004-02-09 10:39:52.000000000 +0000 @@ -855,7 +855,8 @@ /* Initialize the memory controller */ RADEON_WRITE( RADEON_MC_FB_LOCATION, - (dev_priv->gart_vm_start - 1) & 0xffff0000 ); + ( ( dev_priv->gart_vm_start - 1 ) & 0xffff0000 ) + | ( dev_priv->fb_location >> 16 ) ); #if __REALLY_HAVE_AGP if ( !dev_priv->is_pci ) { @@ -1071,13 +1072,6 @@ dev_priv->depth_offset = init->depth_offset; dev_priv->depth_pitch = init->depth_pitch; - dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) | - (dev_priv->front_offset >> 10)); - dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) | - (dev_priv->back_offset >> 10)); - dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) | - (dev_priv->depth_offset >> 10)); - /* Hardware state for depth clears. Remove this if/when we no * longer clear the depth buffer with a 3D rectangle. Hard-code * all values to prevent unwanted 3D state from slipping through @@ -1124,13 +1118,6 @@ return DRM_ERR(EINVAL); } - DRM_FIND_MAP( dev_priv->fb, init->fb_offset ); - if(!dev_priv->fb) { - DRM_ERROR("could not find framebuffer!\n"); - dev->dev_private = (void *)dev_priv; - radeon_do_cleanup_cp(dev); - return DRM_ERR(EINVAL); - } DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); if(!dev_priv->mmio) { DRM_ERROR("could not find mmio region!\n"); @@ -1204,9 +1191,26 @@ dev_priv->buffers->handle ); } + dev_priv->fb_location = ( RADEON_READ( RADEON_MC_FB_LOCATION ) + & 0xffff ) << 16; + + dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) | + ( ( dev_priv->front_offset + + dev_priv->fb_location ) >> 10 ) ); + + dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) | + ( ( dev_priv->back_offset + + dev_priv->fb_location ) >> 10 ) ); + + dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) | + ( ( dev_priv->depth_offset + + dev_priv->fb_location ) >> 10 ) ); + dev_priv->gart_size = init->gart_size; - dev_priv->gart_vm_start = RADEON_READ( RADEON_CONFIG_APER_SIZE ); + dev_priv->gart_vm_start = dev_priv->fb_location + + RADEON_READ( RADEON_CONFIG_APER_SIZE ); + #if __REALLY_HAVE_AGP if ( !dev_priv->is_pci ) dev_priv->gart_buffers_offset = (dev_priv->buffers->offset @@ -1271,12 +1275,12 @@ { DRM_DEBUG( "\n" ); -#if _HAVE_DMA_IRQ +#if __HAVE_IRQ /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. */ - if ( dev->irq ) DRM(irq_uninstall)(dev); + if ( dev->irq_enabled ) DRM(irq_uninstall)(dev); #endif if ( dev->dev_private ) { --- diff/drivers/char/drm/radeon_drm.h 2003-09-30 15:46:12.000000000 +0100 +++ source/drivers/char/drm/radeon_drm.h 2004-02-09 10:39:52.000000000 +0000 @@ -390,6 +390,7 @@ #define DRM_IOCTL_RADEON_IRQ_WAIT DRM_IOW( 0x57, drm_radeon_irq_wait_t) /* added by Charl P. Botha - see radeon_cp.c for details */ #define DRM_IOCTL_RADEON_CP_RESUME DRM_IO(0x58) +#define DRM_IOCTL_RADEON_SETPARAM DRM_IOW(0x59, drm_radeon_setparam_t) typedef struct drm_radeon_init { enum { @@ -502,7 +503,7 @@ } drm_radeon_tex_image_t; typedef struct drm_radeon_texture { - int offset; + unsigned int offset; int pitch; int format; int width; /* Texture image coordinates */ @@ -537,6 +538,7 @@ #define RADEON_PARAM_STATUS_HANDLE 8 #define RADEON_PARAM_SAREA_HANDLE 9 #define RADEON_PARAM_GART_TEX_HANDLE 10 +#define RADEON_PARAM_SCRATCH_OFFSET 11 typedef struct drm_radeon_getparam { int param; @@ -578,4 +580,16 @@ } drm_radeon_irq_wait_t; +/* 1.10: Clients tell the DRM where they think the framebuffer is located in + * the card's address space, via a new generic ioctl to set parameters + */ + +typedef struct drm_radeon_setparam { + unsigned int param; + int64_t value; +} drm_radeon_setparam_t; + +#define RADEON_SETPARAM_FB_LOCATION 1 /* determined framebuffer location */ + + #endif --- diff/drivers/char/drm/radeon_drv.c 2003-07-22 18:54:27.000000000 +0100 +++ source/drivers/char/drm/radeon_drv.c 2004-02-09 10:39:52.000000000 +0000 @@ -48,6 +48,7 @@ #include "drm_fops.h" #include "drm_init.h" #include "drm_ioctl.h" +#include "drm_irq.h" #include "drm_lock.h" #include "drm_memory.h" #include "drm_proc.h" --- diff/drivers/char/drm/radeon_drv.h 2003-09-30 15:46:12.000000000 +0100 +++ source/drivers/char/drm/radeon_drv.h 2004-02-09 10:39:52.000000000 +0000 @@ -73,6 +73,8 @@ drm_radeon_ring_buffer_t ring; drm_radeon_sarea_t *sarea_priv; + u32 fb_location; + int gart_size; u32 gart_vm_start; unsigned long gart_buffers_offset; @@ -133,7 +135,6 @@ unsigned long gart_textures_offset; drm_local_map_t *sarea; - drm_local_map_t *fb; drm_local_map_t *mmio; drm_local_map_t *cp_ring; drm_local_map_t *ring_rptr; @@ -184,6 +185,7 @@ extern int radeon_cp_vertex2( DRM_IOCTL_ARGS ); extern int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ); extern int radeon_cp_getparam( DRM_IOCTL_ARGS ); +extern int radeon_cp_setparam( DRM_IOCTL_ARGS ); extern int radeon_cp_flip( DRM_IOCTL_ARGS ); extern int radeon_mem_alloc( DRM_IOCTL_ARGS ); @@ -239,6 +241,7 @@ #define RADEON_CRTC2_OFFSET 0x0324 #define RADEON_CRTC2_OFFSET_CNTL 0x0328 +#define RADEON_RB3D_COLOROFFSET 0x1c40 #define RADEON_RB3D_COLORPITCH 0x1c48 #define RADEON_DP_GUI_MASTER_CNTL 0x146c @@ -332,6 +335,7 @@ #define RADEON_PP_MISC 0x1c14 #define RADEON_PP_ROT_MATRIX_0 0x1d58 #define RADEON_PP_TXFILTER_0 0x1c54 +#define RADEON_PP_TXOFFSET_0 0x1c5c #define RADEON_PP_TXFILTER_1 0x1c6c #define RADEON_PP_TXFILTER_2 0x1c84 --- diff/drivers/char/drm/radeon_irq.c 2003-05-21 11:50:14.000000000 +0100 +++ source/drivers/char/drm/radeon_irq.c 2004-02-09 10:39:52.000000000 +0000 @@ -54,7 +54,7 @@ * tied to dma at all, this is just a hangover from dri prehistory. */ -irqreturn_t DRM(dma_service)( DRM_IRQ_ARGS ) +irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *) arg; drm_radeon_private_t *dev_priv = --- diff/drivers/char/drm/radeon_state.c 2003-09-30 15:46:12.000000000 +0100 +++ source/drivers/char/drm/radeon_state.c 2004-02-09 10:39:52.000000000 +0000 @@ -36,6 +36,151 @@ /* ================================================================ + * Helper functions for client state checking and fixup + */ + +static __inline__ int radeon_check_and_fixup_offset( drm_radeon_private_t *dev_priv, + drm_file_t *filp_priv, + u32 *offset ) { + u32 off = *offset; + + if ( off >= dev_priv->fb_location && + off < ( dev_priv->gart_vm_start + dev_priv->gart_size ) ) + return 0; + + off += filp_priv->radeon_fb_delta; + + DRM_DEBUG( "offset fixed up to 0x%x\n", off ); + + if ( off < dev_priv->fb_location || + off >= ( dev_priv->gart_vm_start + dev_priv->gart_size ) ) + return DRM_ERR( EINVAL ); + + *offset = off; + + return 0; +} + +static __inline__ int radeon_check_and_fixup_offset_user( drm_radeon_private_t *dev_priv, + drm_file_t *filp_priv, + u32 *offset ) { + u32 off; + + DRM_GET_USER_UNCHECKED( off, offset ); + + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &off ) ) + return DRM_ERR( EINVAL ); + + DRM_PUT_USER_UNCHECKED( offset, off ); + + return 0; +} + +static __inline__ int radeon_check_and_fixup_packets( drm_radeon_private_t *dev_priv, + drm_file_t *filp_priv, + int id, + u32 *data ) { + if ( id == RADEON_EMIT_PP_MISC && + radeon_check_and_fixup_offset_user( dev_priv, filp_priv, + &data[( RADEON_RB3D_DEPTHOFFSET + - RADEON_PP_MISC ) / 4] ) ) { + DRM_ERROR( "Invalid depth buffer offset\n" ); + return DRM_ERR( EINVAL ); + } else if ( id == RADEON_EMIT_PP_CNTL && + radeon_check_and_fixup_offset_user( dev_priv, filp_priv, + &data[( RADEON_RB3D_COLOROFFSET + - RADEON_PP_CNTL ) / 4] ) ) { + DRM_ERROR( "Invalid colour buffer offset\n" ); + return DRM_ERR( EINVAL ); + } else if ( id >= R200_EMIT_PP_TXOFFSET_0 && + id <= R200_EMIT_PP_TXOFFSET_5 && + radeon_check_and_fixup_offset_user( dev_priv, filp_priv, + &data[0] ) ) { + DRM_ERROR( "Invalid R200 texture offset\n" ); + return DRM_ERR( EINVAL ); + } else if ( ( id == RADEON_EMIT_PP_TXFILTER_0 || id == RADEON_EMIT_PP_TXFILTER_1 || + id == RADEON_EMIT_PP_TXFILTER_2 /*|| id == RADEON_EMIT_PP_TXFILTER_3 || + id == RADEON_EMIT_PP_TXFILTER_4 || id == RADEON_EMIT_PP_TXFILTER_5*/ ) && + radeon_check_and_fixup_offset_user( dev_priv, filp_priv, + &data[( RADEON_PP_TXOFFSET_0 + - RADEON_PP_TXFILTER_0 ) / 4] ) ) { + DRM_ERROR( "Invalid R100 texture offset\n" ); + return DRM_ERR( EINVAL ); + } else if ( id == R200_PP_CUBIC_OFFSET_F1_0 || id == R200_PP_CUBIC_OFFSET_F1_1 || + id == R200_PP_CUBIC_OFFSET_F1_2 || id == R200_PP_CUBIC_OFFSET_F1_3 || + id == R200_PP_CUBIC_OFFSET_F1_4 || id == R200_PP_CUBIC_OFFSET_F1_5 ) { + int i; + for ( i = 0; i < 6; i++ ) { + if ( radeon_check_and_fixup_offset_user( dev_priv, + filp_priv, + &data[i] ) ) { + DRM_ERROR( "Invalid R200 cubic texture offset\n" ); + return DRM_ERR( EINVAL ); + } + } + } + + return 0; +} + +static __inline__ int radeon_check_and_fixup_packet3( drm_radeon_private_t *dev_priv, + drm_file_t *filp_priv, + drm_radeon_cmd_buffer_t *cmdbuf, + unsigned int *cmdsz ) { + u32 tmp[4], *cmd = ( u32* )cmdbuf->buf; + + if ( DRM_COPY_FROM_USER_UNCHECKED( tmp, cmd, sizeof( tmp ) ) ) { + DRM_ERROR( "Failed to copy data from user space\n" ); + return DRM_ERR( EFAULT ); + } + + *cmdsz = 2 + ( ( tmp[0] & RADEON_CP_PACKET_COUNT_MASK ) >> 16 ); + + if ( ( tmp[0] & 0xc0000000 ) != RADEON_CP_PACKET3 ) { + DRM_ERROR( "Not a type 3 packet\n" ); + return DRM_ERR( EINVAL ); + } + + if ( 4 * *cmdsz > cmdbuf->bufsz ) { + DRM_ERROR( "Packet size larger than size of data provided\n" ); + return DRM_ERR( EINVAL ); + } + + /* Check client state and fix it up if necessary */ + if ( tmp[0] & 0x8000 ) { /* MSB of opcode: next DWORD GUI_CNTL */ + u32 offset; + + if ( tmp[1] & ( RADEON_GMC_SRC_PITCH_OFFSET_CNTL + | RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) { + offset = tmp[2] << 10; + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) { + DRM_ERROR( "Invalid first packet offset\n" ); + return DRM_ERR( EINVAL ); + } + tmp[2] = ( tmp[2] & 0xffc00000 ) | offset >> 10; + } + + if ( ( tmp[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL ) && + ( tmp[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) { + offset = tmp[3] << 10; + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) { + DRM_ERROR( "Invalid second packet offset\n" ); + return DRM_ERR( EINVAL ); + } + tmp[3] = ( tmp[3] & 0xffc00000 ) | offset >> 10; + } + + if ( DRM_COPY_TO_USER_UNCHECKED( cmd, tmp, sizeof( tmp ) ) ) { + DRM_ERROR( "Failed to copy data to user space\n" ); + return DRM_ERR( EFAULT ); + } + } + + return 0; +} + + +/* ================================================================ * CP hardware state programming functions */ @@ -57,15 +202,28 @@ /* Emit 1.1 state */ -static void radeon_emit_state( drm_radeon_private_t *dev_priv, - drm_radeon_context_regs_t *ctx, - drm_radeon_texture_regs_t *tex, - unsigned int dirty ) +static int radeon_emit_state( drm_radeon_private_t *dev_priv, + drm_file_t *filp_priv, + drm_radeon_context_regs_t *ctx, + drm_radeon_texture_regs_t *tex, + unsigned int dirty ) { RING_LOCALS; DRM_DEBUG( "dirty=0x%08x\n", dirty ); if ( dirty & RADEON_UPLOAD_CONTEXT ) { + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &ctx->rb3d_depthoffset ) ) { + DRM_ERROR( "Invalid depth buffer offset\n" ); + return DRM_ERR( EINVAL ); + } + + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &ctx->rb3d_coloroffset ) ) { + DRM_ERROR( "Invalid depth buffer offset\n" ); + return DRM_ERR( EINVAL ); + } + BEGIN_RING( 14 ); OUT_RING( CP_PACKET0( RADEON_PP_MISC, 6 ) ); OUT_RING( ctx->pp_misc ); @@ -149,6 +307,12 @@ } if ( dirty & RADEON_UPLOAD_TEX0 ) { + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &tex[0].pp_txoffset ) ) { + DRM_ERROR( "Invalid texture offset for unit 0\n" ); + return DRM_ERR( EINVAL ); + } + BEGIN_RING( 9 ); OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_0, 5 ) ); OUT_RING( tex[0].pp_txfilter ); @@ -163,6 +327,12 @@ } if ( dirty & RADEON_UPLOAD_TEX1 ) { + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &tex[1].pp_txoffset ) ) { + DRM_ERROR( "Invalid texture offset for unit 1\n" ); + return DRM_ERR( EINVAL ); + } + BEGIN_RING( 9 ); OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_1, 5 ) ); OUT_RING( tex[1].pp_txfilter ); @@ -177,6 +347,12 @@ } if ( dirty & RADEON_UPLOAD_TEX2 ) { + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &tex[2].pp_txoffset ) ) { + DRM_ERROR( "Invalid texture offset for unit 2\n" ); + return DRM_ERR( EINVAL ); + } + BEGIN_RING( 9 ); OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_2, 5 ) ); OUT_RING( tex[2].pp_txfilter ); @@ -189,12 +365,15 @@ OUT_RING( tex[2].pp_border_color ); ADVANCE_RING(); } + + return 0; } /* Emit 1.2 state */ -static void radeon_emit_state2( drm_radeon_private_t *dev_priv, - drm_radeon_state_t *state ) +static int radeon_emit_state2( drm_radeon_private_t *dev_priv, + drm_file_t *filp_priv, + drm_radeon_state_t *state ) { RING_LOCALS; @@ -206,7 +385,7 @@ ADVANCE_RING(); } - radeon_emit_state( dev_priv, &state->context, + return radeon_emit_state( dev_priv, filp_priv, &state->context, state->tex, state->dirty ); } @@ -1065,6 +1244,7 @@ drm_radeon_tex_image_t *image ) { drm_radeon_private_t *dev_priv = dev->dev_private; + drm_file_t *filp_priv; drm_buf_t *buf; u32 format; u32 *buffer; @@ -1074,6 +1254,13 @@ int i; RING_LOCALS; + DRM_GET_PRIV_WITH_RETURN( filp_priv, filp ); + + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &tex->offset ) ) { + DRM_ERROR( "Invalid destination offset\n" ); + return DRM_ERR( EINVAL ); + } + dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD; /* Flush the pixel cache. This ensures no pixel data gets mixed @@ -1221,7 +1408,7 @@ /* Update the input parameters for next time */ image->y += height; image->height -= height; - (const u8 *)image->data += size; + image->data = (const u8 *)image->data + size; } while (image->height > 0); /* Flush the pixel cache after the blit completes. This ensures @@ -1377,6 +1564,7 @@ { DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; + drm_file_t *filp_priv; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf; @@ -1390,6 +1578,8 @@ return DRM_ERR(EINVAL); } + DRM_GET_PRIV_WITH_RETURN( filp_priv, filp ); + DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex_t *)data, sizeof(vertex) ); @@ -1429,11 +1619,14 @@ buf->used = vertex.count; /* not used? */ if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) { - radeon_emit_state( dev_priv, - &sarea_priv->context_state, - sarea_priv->tex_state, - sarea_priv->dirty ); - + if ( radeon_emit_state( dev_priv, filp_priv, + &sarea_priv->context_state, + sarea_priv->tex_state, + sarea_priv->dirty ) ) { + DRM_ERROR( "radeon_emit_state failed\n" ); + return DRM_ERR( EINVAL ); + } + sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES | RADEON_UPLOAD_TEX1IMAGES | RADEON_UPLOAD_TEX2IMAGES | @@ -1461,6 +1654,7 @@ { DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; + drm_file_t *filp_priv; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf; @@ -1475,6 +1669,8 @@ return DRM_ERR(EINVAL); } + DRM_GET_PRIV_WITH_RETURN( filp_priv, filp ); + DRM_COPY_FROM_USER_IOCTL( elts, (drm_radeon_indices_t *)data, sizeof(elts) ); @@ -1523,10 +1719,13 @@ buf->used = elts.end; if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) { - radeon_emit_state( dev_priv, - &sarea_priv->context_state, - sarea_priv->tex_state, - sarea_priv->dirty ); + if ( radeon_emit_state( dev_priv, filp_priv, + &sarea_priv->context_state, + sarea_priv->tex_state, + sarea_priv->dirty ) ) { + DRM_ERROR( "radeon_emit_state failed\n" ); + return DRM_ERR( EINVAL ); + } sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES | RADEON_UPLOAD_TEX1IMAGES | @@ -1686,6 +1885,7 @@ { DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; + drm_file_t *filp_priv; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf; @@ -1700,6 +1900,8 @@ return DRM_ERR(EINVAL); } + DRM_GET_PRIV_WITH_RETURN( filp_priv, filp ); + DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex2_t *)data, sizeof(vertex) ); @@ -1747,7 +1949,10 @@ sizeof(state) ) ) return DRM_ERR(EFAULT); - radeon_emit_state2( dev_priv, &state ); + if ( radeon_emit_state2( dev_priv, filp_priv, &state ) ) { + DRM_ERROR( "radeon_emit_state2 failed\n" ); + return DRM_ERR( EINVAL ); + } laststate = prim.stateidx; } @@ -1784,6 +1989,7 @@ static int radeon_emit_packets( drm_radeon_private_t *dev_priv, + drm_file_t *filp_priv, drm_radeon_cmd_header_t header, drm_radeon_cmd_buffer_t *cmdbuf ) { @@ -1798,8 +2004,15 @@ sz = packet[id].len; reg = packet[id].start; - if (sz * sizeof(int) > cmdbuf->bufsz) + if (sz * sizeof(int) > cmdbuf->bufsz) { + DRM_ERROR( "Packet size provided larger than data provided\n" ); return DRM_ERR(EINVAL); + } + + if ( radeon_check_and_fixup_packets( dev_priv, filp_priv, id, data ) ) { + DRM_ERROR( "Packet verification failed\n" ); + return DRM_ERR( EINVAL ); + } BEGIN_RING(sz+1); OUT_RING( CP_PACKET0( reg, (sz-1) ) ); @@ -1882,24 +2095,21 @@ static int radeon_emit_packet3( drm_device_t *dev, + drm_file_t *filp_priv, drm_radeon_cmd_buffer_t *cmdbuf ) { drm_radeon_private_t *dev_priv = dev->dev_private; - int cmdsz, tmp; - int *cmd = (int *)cmdbuf->buf; + unsigned int cmdsz; + int *cmd = (int *)cmdbuf->buf, ret; RING_LOCALS; - DRM_DEBUG("\n"); - if (DRM_GET_USER_UNCHECKED( tmp, &cmd[0])) - return DRM_ERR(EFAULT); - - cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16); - - if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 || - cmdsz * 4 > cmdbuf->bufsz) - return DRM_ERR(EINVAL); + if ( ( ret = radeon_check_and_fixup_packet3( dev_priv, filp_priv, + cmdbuf, &cmdsz ) ) ) { + DRM_ERROR( "Packet verification failed\n" ); + return ret; + } BEGIN_RING( cmdsz ); OUT_RING_USER_TABLE( cmd, cmdsz ); @@ -1912,27 +2122,25 @@ static int radeon_emit_packet3_cliprect( drm_device_t *dev, + drm_file_t *filp_priv, drm_radeon_cmd_buffer_t *cmdbuf, int orig_nbox ) { drm_radeon_private_t *dev_priv = dev->dev_private; drm_clip_rect_t box; - int cmdsz, tmp; - int *cmd = (int *)cmdbuf->buf; + unsigned int cmdsz; + int *cmd = (int *)cmdbuf->buf, ret; drm_clip_rect_t *boxes = cmdbuf->boxes; int i = 0; RING_LOCALS; DRM_DEBUG("\n"); - if (DRM_GET_USER_UNCHECKED( tmp, &cmd[0])) - return DRM_ERR(EFAULT); - - cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16); - - if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 || - cmdsz * 4 > cmdbuf->bufsz) - return DRM_ERR(EINVAL); + if ( ( ret = radeon_check_and_fixup_packet3( dev_priv, filp_priv, + cmdbuf, &cmdsz ) ) ) { + DRM_ERROR( "Packet verification failed\n" ); + return ret; + } if (!orig_nbox) goto out; @@ -2009,6 +2217,7 @@ { DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; + drm_file_t *filp_priv; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf = 0; int idx; @@ -2023,6 +2232,8 @@ return DRM_ERR(EINVAL); } + DRM_GET_PRIV_WITH_RETURN( filp_priv, filp ); + DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_radeon_cmd_buffer_t *)data, sizeof(cmdbuf) ); @@ -2053,7 +2264,7 @@ switch (header.header.cmd_type) { case RADEON_CMD_PACKET: DRM_DEBUG("RADEON_CMD_PACKET\n"); - if (radeon_emit_packets( dev_priv, header, &cmdbuf )) { + if (radeon_emit_packets( dev_priv, filp_priv, header, &cmdbuf )) { DRM_ERROR("radeon_emit_packets failed\n"); return DRM_ERR(EINVAL); } @@ -2096,7 +2307,7 @@ case RADEON_CMD_PACKET3: DRM_DEBUG("RADEON_CMD_PACKET3\n"); - if (radeon_emit_packet3( dev, &cmdbuf )) { + if (radeon_emit_packet3( dev, filp_priv, &cmdbuf )) { DRM_ERROR("radeon_emit_packet3 failed\n"); return DRM_ERR(EINVAL); } @@ -2104,7 +2315,7 @@ case RADEON_CMD_PACKET3_CLIP: DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n"); - if (radeon_emit_packet3_cliprect( dev, &cmdbuf, orig_nbox )) { + if (radeon_emit_packet3_cliprect( dev, filp_priv, &cmdbuf, orig_nbox )) { DRM_ERROR("radeon_emit_packet3_clip failed\n"); return DRM_ERR(EINVAL); } @@ -2203,3 +2414,31 @@ return 0; } + +int radeon_cp_setparam( DRM_IOCTL_ARGS ) { + DRM_DEVICE; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_file_t *filp_priv; + drm_radeon_setparam_t sp; + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return DRM_ERR( EINVAL ); + } + + DRM_GET_PRIV_WITH_RETURN( filp_priv, filp ); + + DRM_COPY_FROM_USER_IOCTL( sp, ( drm_radeon_setparam_t* )data, + sizeof( sp ) ); + + switch( sp.param ) { + case RADEON_SETPARAM_FB_LOCATION: + filp_priv->radeon_fb_delta = dev_priv->fb_location - sp.value; + break; + default: + DRM_DEBUG( "Invalid parameter %d\n", sp.param ); + return DRM_ERR( EINVAL ); + } + + return 0; +} --- diff/drivers/char/drm/sis.h 2003-09-30 15:46:12.000000000 +0100 +++ source/drivers/char/drm/sis.h 2004-02-09 10:39:52.000000000 +0000 @@ -62,6 +62,13 @@ [DRM_IOCTL_NR(DRM_IOCTL_SIS_AGP_FREE)] = { sis_ioctl_agp_free, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_SIS_FB_INIT)] = { sis_fb_init, 1, 1 } +#define DRIVER_PCI_IDS \ + {0x1039, 0x0300, 0, "SiS 300/305"}, \ + {0x1039, 0x5300, 0, "SiS 540"}, \ + {0x1039, 0x6300, 0, "SiS 630"}, \ + {0x1039, 0x7300, 0, "SiS 730"}, \ + {0, 0, 0, NULL} + #define __HAVE_COUNTERS 5 /* Buffer customization: --- diff/drivers/char/drm/sis_mm.c 2003-09-30 15:46:12.000000000 +0100 +++ source/drivers/char/drm/sis_mm.c 2004-02-09 10:39:52.000000000 +0000 @@ -34,7 +34,11 @@ #include "sis_drv.h" #include "sis_ds.h" #if defined(__linux__) && defined(CONFIG_FB_SIS) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) #include